/* Copyright (c) 2015 Adam Marcionek, All Rights Reserved
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package com.sun.jna.platform.win32;
import java.io.File;
import com.sun.jna.Memory;
import com.sun.jna.platform.win32.LMShare.SHARE_INFO_2;
import com.sun.jna.platform.win32.WinNT.HANDLEByReference;
import com.sun.jna.platform.win32.Winnetwk.ConnectFlag;
import com.sun.jna.platform.win32.Winnetwk.NETRESOURCE;
import com.sun.jna.platform.win32.Winnetwk.REMOTE_NAME_INFO;
import com.sun.jna.platform.win32.Winnetwk.RESOURCESCOPE;
import com.sun.jna.platform.win32.Winnetwk.RESOURCETYPE;
import com.sun.jna.platform.win32.Winnetwk.RESOURCEUSAGE;
import com.sun.jna.platform.win32.Winnetwk.UNIVERSAL_NAME_INFO;
import com.sun.jna.ptr.IntByReference;
import junit.framework.TestCase;
/**
* @author amarcionek[at]gmail[dot]com
*/
public class MprTest extends TestCase {
public static void main(String[] args) throws Exception {
junit.textui.TestRunner.run(MprTest.class);
}
public void testCreateLocalShare() throws Exception {
File fileShareFolder = createTempFolder();
String share = createLocalShare(fileShareFolder);
Netapi32.INSTANCE.NetShareDel(null, share, 0);
}
public void testWNetUseConnection() throws Exception {
// First create a share on the local machine
File fileShareFolder = createTempFolder();
String share = createLocalShare(fileShareFolder);
NETRESOURCE resource = new NETRESOURCE();
resource.dwDisplayType = 0;
resource.dwScope = 0;
resource.dwType = RESOURCETYPE.RESOURCETYPE_DISK;
resource.lpRemoteName = "\\\\" + getLocalComputerName() + "\\" + share;
try {
// Cancel any existing connections of the same name
Mpr.INSTANCE.WNetCancelConnection2(resource.lpRemoteName, 0, true);
// Establish a new one
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetUseConnection(null, resource, null, null, 0, null, null, null));
} finally {
// Clean up resources
Mpr.INSTANCE.WNetCancelConnection2(resource.lpRemoteName, 0, true);
Netapi32.INSTANCE.NetShareDel(null, share, 0);
fileShareFolder.delete();
}
}
public void testWNetAddConnection3() throws Exception {
// First create a share on the local machine
File fileShareFolder = createTempFolder();
String share = createLocalShare(fileShareFolder);
NETRESOURCE resource = new NETRESOURCE();
resource.dwDisplayType = 0;
resource.dwScope = 0;
resource.dwType = RESOURCETYPE.RESOURCETYPE_DISK;
resource.lpRemoteName = "\\\\" + getLocalComputerName() + "\\" + share;
try {
// Cancel any existing connections of the same name
Mpr.INSTANCE.WNetCancelConnection2(resource.lpRemoteName, 0, true);
// Establish a new one
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetAddConnection3(null, resource, null, null, 0));
} finally {
// Clean up resources
Mpr.INSTANCE.WNetCancelConnection2(resource.lpRemoteName, 0, true);
Netapi32.INSTANCE.NetShareDel(null, share, 0);
fileShareFolder.delete();
}
}
public void testWNetOpenCloseConnection() throws Exception {
HANDLEByReference lphEnum = new HANDLEByReference();
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetOpenEnum(RESOURCESCOPE.RESOURCE_CONNECTED, RESOURCETYPE.RESOURCETYPE_DISK,
RESOURCEUSAGE.RESOURCEUSAGE_ALL, null, lphEnum));
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetCloseEnum(lphEnum.getValue()));
}
public void testWNetEnumConnection() throws Exception {
int bufferSize = 16 * 1024; // MSDN recommends this as a reasonable size
HANDLEByReference lphEnum = new HANDLEByReference();
// Create a local share and connect to it. This ensures the enum will
// find at least one entry.
File fileShareFolder = createTempFolder();
String share = createLocalShare(fileShareFolder);
// Connect to local share
connectToLocalShare(share, null);
try {
// Open an enumeration
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetOpenEnum(RESOURCESCOPE.RESOURCE_CONNECTED, RESOURCETYPE.RESOURCETYPE_DISK,
RESOURCEUSAGE.RESOURCEUSAGE_ALL, null, lphEnum));
int winError = WinError.ERROR_SUCCESS;
while (true) {
Memory memory = new Memory(bufferSize);
IntByReference lpBufferSize = new IntByReference(bufferSize);
IntByReference lpcCount = new IntByReference(1);
// Get next value
winError = Mpr.INSTANCE.WNetEnumResource(lphEnum.getValue(), lpcCount, memory, lpBufferSize);
// Reached end of enumeration
if (winError == WinError.ERROR_NO_MORE_ITEMS)
break;
// Unlikely, but means our buffer size isn't large enough.
if (winError == WinError.ERROR_MORE_DATA) {
bufferSize = bufferSize * 2;
continue;
}
// If we get here, it means it has to be a success or our
// programming logic was wrong.
assertEquals(winError, WinError.ERROR_SUCCESS);
// Asked for one, should only get one.
assertEquals(1, lpcCount.getValue());
// Create a NETRESOURCE based on the memory
NETRESOURCE resource = new NETRESOURCE(memory);
// Assert things we know for sure.
assertNotNull(resource.lpRemoteName);
}
// Expect ERROR_NO_MORE_ITEMS here.
assertEquals(winError, WinError.ERROR_NO_MORE_ITEMS);
} finally {
// Clean up resources
Mpr.INSTANCE.WNetCloseEnum(lphEnum.getValue());
disconnectFromLocalShare("\\\\" + getLocalComputerName() + "\\" + share);
deleteLocalShare(share);
fileShareFolder.delete();
}
}
public void testWNetGetUniversalName() throws Exception {
int bufferSize = 1024; // MSDN recommends this as a reasonable size
Memory memory = new Memory(bufferSize);
IntByReference lpBufferSize = new IntByReference(bufferSize);
File file = null;
String share = null;
String driveLetter = new String("x:");
File fileShareFolder = createTempFolder();
try {
// Create a local share and connect to it.
share = createLocalShare(fileShareFolder);
// Connect to share using a drive letter.
connectToLocalShare(share, driveLetter);
// Create a path on local device redirected to the share.
String filePath = new String(driveLetter + "\\testfile.txt");
file = new File(filePath);
file.createNewFile();
// Test WNetGetUniversalName using UNIVERSAL_NAME_INFO_LEVEL
assertEquals(WinError.ERROR_SUCCESS,
Mpr.INSTANCE.WNetGetUniversalName(filePath, Winnetwk.UNIVERSAL_NAME_INFO_LEVEL, memory, lpBufferSize));
UNIVERSAL_NAME_INFO uinfo = new UNIVERSAL_NAME_INFO(memory);
assertNotNull(uinfo.lpUniversalName);
// Test WNetGetUniversalName using REMOTE_NAME_INFO_LEVEL
assertEquals(WinError.ERROR_SUCCESS,
Mpr.INSTANCE.WNetGetUniversalName(filePath, Winnetwk.REMOTE_NAME_INFO_LEVEL, memory, lpBufferSize));
REMOTE_NAME_INFO rinfo = new REMOTE_NAME_INFO(memory);
assertNotNull(rinfo.lpUniversalName);
assertNotNull(rinfo.lpConnectionName);
assertNotNull(rinfo.lpRemainingPath);
} finally {
// Clean up resources
if (file != null)
file.delete();
if (share != null) {
disconnectFromLocalShare(driveLetter);
deleteLocalShare(share);
fileShareFolder.delete();
}
}
}
private static File createTempFolder() throws Exception {
String folderPath = System.getProperty("java.io.tmpdir") + File.separatorChar + System.nanoTime();
File file = new File(folderPath);
file.mkdir();
return file;
}
/**
* Get local NETBIOS machine name
*
* @return String with machine name
* @throws Exception
*/
private String getLocalComputerName() throws Exception {
IntByReference lpnSize = new IntByReference(0);
// Get size of char array
Kernel32.INSTANCE.GetComputerName(null, lpnSize);
assertEquals(WinError.ERROR_BUFFER_OVERFLOW, Kernel32.INSTANCE.GetLastError());
// Allocate character array
char buffer[] = new char[WinBase.MAX_COMPUTERNAME_LENGTH + 1];
lpnSize.setValue(buffer.length);
assertTrue(Kernel32.INSTANCE.GetComputerName(buffer, lpnSize));
// Return string with computer name
String computerName = new String(buffer);
computerName = computerName.trim();
return computerName;
}
/**
* Create a share on the local machine. Uses a temporary directory and
* shares it out with ACCESS_ALL
*
* @param shareFolder
* the full path local folder to share
* @return String with the share name, essentially the top level folder
* name.
* @throws Exception
* the exception
*/
private String createLocalShare(File shareFolder) throws Exception {
SHARE_INFO_2 shi = new SHARE_INFO_2();
shi.shi2_netname = shareFolder.getName();
shi.shi2_type = LMShare.STYPE_DISKTREE;
shi.shi2_remark = "";
shi.shi2_permissions = LMAccess.ACCESS_ALL;
shi.shi2_max_uses = -1;
shi.shi2_current_uses = 0;
shi.shi2_path = shareFolder.getAbsolutePath();
shi.shi2_passwd = "";
// Write from struct to native memory.
shi.write();
IntByReference parm_err = new IntByReference(0);
int errorCode = Netapi32.INSTANCE.NetShareAdd(null, // Use local computer
2, shi.getPointer(), parm_err);
assertEquals(
String.format("Failed to create share - errorCode: %d (Param: %d)", errorCode, parm_err.getValue()),
LMErr.NERR_Success, errorCode);
return shareFolder.getName();
}
/**
* Delete a local share
*
* @param share
*/
private void deleteLocalShare(String share) {
Netapi32.INSTANCE.NetShareDel(null, share, 0);
}
/**
* Connect to a local share on the local machine. Assumes the share is
* already present
*
* @param share
* name of share on local computer.
* @param lpLocalName
* name of local device to redirect to. E.g. F:. If null, makes a
* connection without redirecting.
* @throws Exception
* the exception
*/
private void connectToLocalShare(String share, String lpLocalName) throws Exception {
NETRESOURCE resource = new NETRESOURCE();
resource.dwDisplayType = 0;
resource.dwScope = 0;
resource.dwType = RESOURCETYPE.RESOURCETYPE_DISK;
resource.lpLocalName = lpLocalName;
resource.lpRemoteName = "\\\\" + getLocalComputerName() + "\\" + share;
// Establish connection
assertEquals(WinError.ERROR_SUCCESS, Mpr.INSTANCE.WNetAddConnection3(null, resource, null, null, 0));
}
/**
* Disconnect from a share.
*
* @param lpName
* [in] Pointer to a constant null-terminated string that
* specifies the name of either the redirected local device or
* the remote network resource to disconnect from. If this
* parameter specifies a redirected local device, the function
* cancels only the specified device redirection. If the
* parameter specifies a remote network resource, all connections
* without devices are canceled.
*/
private void disconnectFromLocalShare(String lpName) {
// Remove connection
Mpr.INSTANCE.WNetCancelConnection2(lpName, ConnectFlag.CONNECT_UPDATE_PROFILE, true);
}
}