I'm trying to call wglMakeCurrent using C# native call [DllImport] attribute. The function works and set my opengl context as current.
The thing is sometimes it throws error. It has no pattern, it just fails to make the context current.
I reproduced the same code in c++ and it doesnt have that problem.
My first idea is that it's something related to being HDC or HGLRC handle is not properly disposed or something still keeps alive the handles but I have implemented a cleanup procedure when window is closing I both release HDC and delete HGLRC. In the and it does not work.
Here its the code
public enum PixelFormatDescriptorFlags : uint
{
PFD_MAIN_PLANE = 0,
PFD_OVERLAY_PLANE = 1,
PFD_TYPE_RGBA = 0,
PFD_TYPE_COLORINDEX = 1,
PFD_DOUBLEBUFFER = 0x00000001,
PFD_DRAW_TO_WINDOW = 0x00000004,
PFD_DRAW_TO_BITMAP = 0x00000008,
PFD_SUPPORT_GDI = 0x00000010,
PFD_SUPPORT_OPENGL = 0x00000020,
PFD_GENERIC_FORMAT = 0x00000040,
PFD_NEED_PALETTE = 0x00000080,
PFD_NEED_SYSTEM_PALETTE = 0x00000100,
PFD_SWAP_EXCHANGE = 0x00000200,
PFD_SWAP_COPY = 0x00000400,
PFD_SWAP_LAYER_BUFFERS = 0x00000800,
PFD_GENERIC_ACCELERATED = 0x00001000,
PFD_SUPPORT_DIRECTDRAW = 0x00002000,
PFD_DIRECT3D_ACCELERATED = 0x00004000,
PFD_SUPPORT_COMPOSITION = 0x00008000,
PFD_DEPTH_DONTCARE = 0x20000000,
PFD_DOUBLEBUFFER_DONTCARE = 0x40000000,
PFD_STEREO_DONTCARE = 0x80000000
}
public struct HGLRC
{
public int Hglrc;
}
public struct PIXELFORMATDESCRIPTOR
{
public ushort nSize;
public ushort nVersion;
public UInt32 dwFlags;
public byte iPixelType;
public byte cColorBits;
public byte cRedBits;
public byte cRedShift;
public byte cGreenBits;
public byte cGreenShift;
public byte cBlueBits;
public byte cBlueShift;
public byte cAlphaBits;
public byte cAlphaShift;
public byte cAccumBits;
public byte cAccumRedBits;
public byte cAccumGreenBits;
public byte cAccumBlueBits;
public byte cAccumAlphaBits;
public byte cDepthBits;
public byte cStencilBits;
public byte cAuxBuffers;
public byte iLayerType;
public byte bReserved;
public UInt32 dwLayerMask;
public UInt32 dwVisibleMask;
public UInt32 dwDamageMask;
}
public static class Win32GL
{
[System.Runtime.InteropServices.DllImport("ZeroGDIInterface.dll", SetLastError = true)]
public static extern int ChoosePixelFormatGDI(Win32HDC hdc,ref PIXELFORMATDESCRIPTOR desc);
[System.Runtime.InteropServices.DllImport("ZeroGDIInterface.dll", SetLastError = true)]
public static extern int SetPixelFormatGDI(Win32HDC hdc,int format, ref PIXELFORMATDESCRIPTOR desc);
[System.Runtime.InteropServices.DllImport("ZeroGDIInterface.dll", SetLastError = true)]
public static extern HGLRC wglCreateContextGDI(Win32HDC hdc);
[System.Runtime.InteropServices.DllImport("ZeroGDIInterface.dll", SetLastError = true)]
public static extern int wglMakeCurrentGDI(Win32HDC hdc,HGLRC hglrc);
[System.Runtime.InteropServices.DllImport("ZeroGDIInterface.dll", SetLastError = true)]
public static extern int wglDeleteContextGDI(HGLRC hglrc);
}
WindowsWindow win32Window = ownerWindow as WindowsWindow;
PIXELFORMATDESCRIPTOR pfd = new PIXELFORMATDESCRIPTOR();
pfd.nSize = (short)Marshal.SizeOf<PIXELFORMATDESCRIPTOR>();
pfd.dwFlags = (uint)(PixelFormatDescriptorFlags.PFD_DRAW_TO_WINDOW | PixelFormatDescriptorFlags.PFD_SUPPORT_OPENGL | PixelFormatDescriptorFlags.PFD_DOUBLEBUFFER);
pfd.iPixelType = (byte)PixelFormatDescriptorFlags.PFD_TYPE_RGBA;
pfd.nVersion = 1;
pfd.cColorBits = 32;
pfd.cAlphaBits = 8;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = (byte)PixelFormatDescriptorFlags.PFD_MAIN_PLANE;
int pixelFormat = Win32GL.ChoosePixelFormatGDI(win32Window.Hdc, ref pfd);
if(pixelFormat == 0)
{
throw new Exception("Choose pixel format failed!");
}
if (Win32GL.SetPixelFormatGDI(win32Window.Hdc, pixelFormat, ref pfd) == 0)
{
throw new Exception("Set pixel format failed!");
}
HGLRC dummyContext = Win32GL.wglCreateContextGDI(win32Window.Hdc);
if(dummyContext.Hglrc == 0)
{
throw new Exception("Failed to create wgl context");
}
if (Win32GL.wglMakeCurrentGDI(win32Window.Hdc, dummyContext) == 0)
{
throw new Exception("Failed to make the dummy context current! = ");
}
Edit: When it does not throw error, I can simply use the context for clear color and swapping the swapchain buffers. So native bindings and the code works as intended
Edit: Added the [DllImport] and used structures
Related
I am currently working on a custom explorer and would like to allow the user to use the explorer on a remote computer, but still access the drives on their own computer.
Now, I have already read a lot of information on this subject and apparently I need to use WNetOpenEnum and WNetEnumResource to get an enumeration of network resources (see this thread). Unfortunately, I have not yet been successful in doing so.
So I was wondering if there is an easier way to access the paths of the drives.
One possibility would be to simply check all common names for their existence (\\tsclient\C , \\tsclient\D etc.). Not a very good one, though.
So before I get any further into making WNetEnumResource work, I thought I'd check to see if I've overlooked something that makes it easy to return all tsclient paths. Any help is welcome.
Thanks in advance.
Finally found a working solution:
class Program
{
[STAThread]
static void Main(string[] args)
{
WNETOE(null);
}
// Coded by Eugene E. Zhukovsky, 8.21.2002
// Added by Kill
// declare the DLL import functions
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
public static extern int WNetEnumResource(
IntPtr hEnum,
ref int lpcCount,
IntPtr lpBuffer,
ref int lpBufferSize);
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
public static extern int WNetOpenEnum(
RESOURCE_SCOPE dwScope,
RESOURCE_TYPE dwType,
RESOURCE_USAGE dwUsage,
[MarshalAs(UnmanagedType.AsAny)][In] Object lpNetResource,
out IntPtr lphEnum);
[DllImport("mpr.dll", CharSet = CharSet.Auto)]
public static extern int WNetCloseEnum(IntPtr hEnum);
//declare the structures to hold info
public enum RESOURCE_SCOPE
{
RESOURCE_CONNECTED = 0x00000001,
RESOURCE_GLOBALNET = 0x00000002,
RESOURCE_REMEMBERED = 0x00000003,
RESOURCE_RECENT = 0x00000004,
RESOURCE_CONTEXT = 0x00000005
}
public enum RESOURCE_TYPE
{
RESOURCETYPE_ANY = 0x00000000,
RESOURCETYPE_DISK = 0x00000001,
RESOURCETYPE_PRINT = 0x00000002,
RESOURCETYPE_RESERVED = 0x00000008,
}
public enum RESOURCE_USAGE
{
RESOURCEUSAGE_CONNECTABLE = 0x00000001,
RESOURCEUSAGE_CONTAINER = 0x00000002,
RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
RESOURCEUSAGE_SIBLING = 0x00000008,
RESOURCEUSAGE_ATTACHED = 0x00000010,
RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
}
public enum RESOURCE_DISPLAYTYPE
{
RESOURCEDISPLAYTYPE_GENERIC = 0x00000000,
RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001,
RESOURCEDISPLAYTYPE_SERVER = 0x00000002,
RESOURCEDISPLAYTYPE_SHARE = 0x00000003,
RESOURCEDISPLAYTYPE_FILE = 0x00000004,
RESOURCEDISPLAYTYPE_GROUP = 0x00000005,
RESOURCEDISPLAYTYPE_NETWORK = 0x00000006,
RESOURCEDISPLAYTYPE_ROOT = 0x00000007,
RESOURCEDISPLAYTYPE_SHAREADMIN = 0x00000008,
RESOURCEDISPLAYTYPE_DIRECTORY = 0x00000009,
RESOURCEDISPLAYTYPE_TREE = 0x0000000A,
RESOURCEDISPLAYTYPE_NDSCONTAINER = 0x0000000B
}
public struct NETRESOURCE
{
public RESOURCE_SCOPE dwScope;
public RESOURCE_TYPE dwType;
public RESOURCE_DISPLAYTYPE dwDisplayType;
public RESOURCE_USAGE dwUsage;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)] public string lpLocalName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)] public string lpRemoteName;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)] public string lpComment;
[MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPTStr)] public string lpProvider;
}
//the function we'll be calling
public static void WNETOE(Object o)
{
int iRet;
IntPtr ptrHandle = new IntPtr();
try
{
iRet = WNetOpenEnum(
RESOURCE_SCOPE.RESOURCE_GLOBALNET,
RESOURCE_TYPE.RESOURCETYPE_ANY,
RESOURCE_USAGE.RESOURCEUSAGE_ALL,
o,
out ptrHandle);
if (iRet != 0)
{
return;
}
int entries;
int buffer = 16384;
IntPtr ptrBuffer = Marshal.AllocHGlobal(buffer);
NETRESOURCE nr;
for (; ; )
{
entries = -1;
buffer = 16384;
iRet = WNetEnumResource(ptrHandle, ref entries, ptrBuffer, ref buffer);
if ((iRet != 0) || (entries < 1))
{
break;
}
IntPtr ptr = ptrBuffer;
for (int i = 0; i < entries; i++)
{
nr = (NETRESOURCE)Marshal.PtrToStructure(ptr, typeof(NETRESOURCE));
if (RESOURCE_USAGE.RESOURCEUSAGE_CONTAINER == (nr.dwUsage
& RESOURCE_USAGE.RESOURCEUSAGE_CONTAINER))
{
//call recursively to get all entries in a container
WNETOE(nr);
}
ptr += Marshal.SizeOf(nr);
Console.WriteLine(" {0} : LocalName='{1}' RemoteName='{2}'",
nr.dwDisplayType.ToString(), nr.lpLocalName, nr.lpRemoteName);
}
}
Marshal.FreeHGlobal(ptrBuffer);
iRet = WNetCloseEnum(ptrHandle);
}
catch (Exception e)
{
}
}
//here's some possible error codes
public enum NERR
{
NERR_Success = 0,/* Success */
ERROR_MORE_DATA = 234, // dderror
ERROR_NO_BROWSER_SERVERS_FOUND = 6118,
ERROR_INVALID_LEVEL = 124,
ERROR_ACCESS_DENIED = 5,
ERROR_INVALID_PARAMETER = 87,
ERROR_NOT_ENOUGH_MEMORY = 8,
ERROR_NETWORK_BUSY = 54,
ERROR_BAD_NETPATH = 53,
ERROR_NO_NETWORK = 1222,
ERROR_INVALID_HANDLE_STATE = 1609,
ERROR_EXTENDED_ERROR = 1208
}
}
How would you write this type of struct in c#?
struct _JOBOBJECT_BASIC_PROCESS_ID_LIST {
DWORD NumberOfAssignedProcesses;
DWORD NumberOfProcessIdsInList;
ULONG_PTR ProcessIdList[1];
}
sins there is no set size for the ProcessIdList array, what do you do? Do you just write it like this:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
IntPtr ProcessIdList; //Must point to a allocated array, thanks jdweng for letting me know.
}
or do you just assign a size which is big enough, e.g.:
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATH)]
UIntPtr[] ProcessIdList; //Works just fine, but is limited to the SizeConst.
}
This sort of structure is usually declared (there are others like this one in WLan APIs for example) :
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
public int NumberOfAssignedProcesses;
public int NumberOfProcessIdsInList;
public IntPtr[] ProcessIdList;
public JOBOBJECT_BASIC_PROCESS_ID_LIST(IntPtr pList)
{
int nIntSize = Marshal.SizeOf<int>(); // 4
NumberOfAssignedProcesses = Marshal.ReadInt32(pList, 0);
NumberOfProcessIdsInList = Marshal.ReadInt32(pList, nIntSize);
ProcessIdList = new IntPtr[NumberOfProcessIdsInList];
for (int i = 0; i < NumberOfProcessIdsInList; i++)
{
IntPtr pItemList = IntPtr.Zero;
if (Marshal.SizeOf<IntPtr>() == 4)
pItemList = new IntPtr(pList.ToInt32() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
else
pItemList = new IntPtr(pList.ToInt64() + (i * Marshal.SizeOf<IntPtr>()) + (nIntSize * 2));
IntPtr nPID = new IntPtr();
nPID = Marshal.ReadIntPtr(pItemList, 0);
ProcessIdList[i] = nPID;
}
}
}
A test with 5 Notepad launched and assigned to a job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE,
then QueryInformationJobObject to enumerate the PIDs by using this structure =>
private IntPtr hJob = IntPtr.Zero;
bool bRet = false;
hJob = CreateJobObject(IntPtr.Zero, "Test Job Object");
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jbeli = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
jbeli.BasicLimitInformation.LimitFlags |= (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_BREAKAWAY_OK);
int nLength = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr pJobInfo = Marshal.AllocHGlobal(nLength);
Marshal.StructureToPtr(jbeli, pJobInfo, false);
SetInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectExtendedLimitInformation, pJobInfo, (uint)nLength);
Marshal.FreeHGlobal(pJobInfo);
int nNbProcesses = 5;
for (int i = 0; i < nNbProcesses; i++)
{
using (Process exeProcess = new Process())
{
exeProcess.StartInfo.FileName = "notepad";
exeProcess.Start();
exeProcess.WaitForInputIdle();
IntPtr hProcess = exeProcess.Handle;
bRet = AssignProcessToJobObject(hJob, hProcess);
}
}
JOBOBJECT_BASIC_PROCESS_ID_LIST jobpil = new JOBOBJECT_BASIC_PROCESS_ID_LIST();
jobpil.NumberOfAssignedProcesses = nNbProcesses;
int nSize = Marshal.SizeOf<JOBOBJECT_BASIC_PROCESS_ID_LIST>() + (nNbProcesses - 1) * Marshal.SizeOf<IntPtr>();
IntPtr pJobpil = Marshal.AllocHGlobal(nSize);
Marshal.StructureToPtr(jobpil, pJobpil, false);
int nReturnLength = 0;
bRet = QueryInformationJobObject(hJob, JOBOBJECTINFOCLASS.JobObjectBasicProcessIdList, pJobpil, nSize, out nReturnLength);
if (bRet)
{
var processidlist = new JOBOBJECT_BASIC_PROCESS_ID_LIST(pJobpil);
foreach (var pid in processidlist.ProcessIdList)
{
Console.WriteLine("PID: {0}", pid.ToString());
}
}
else
{
int nErr = Marshal.GetLastWin32Error();
Win32Exception win32Exception = new Win32Exception(nErr);
this.Activate();
MessageBox.Show("Error: " + win32Exception.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Marshal.FreeHGlobal(pJobpil);
// CloseHandle can be added in Form1_FormClosed :
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
CloseHandle(hJob);
}
Declarations =>
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInformationClass, [Out, MarshalAs(UnmanagedType.SysUInt)] IntPtr lpJobObjectInformation, int cbJobObjectInformationLength, out int lpReturnLength);
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_BASIC_LIMIT_INFORMATION
{
public ulong PerProcessUserTimeLimit;
public ulong PerJobUserTimeLimit;
public int LimitFlags;
public IntPtr MinimumWorkingSetSize;
public IntPtr MaximumWorkingSetSize;
public int ActiveProcessLimit;
public IntPtr Affinity;
public int PriorityClass;
public int SchedulingClass;
}
[StructLayout(LayoutKind.Sequential)]
struct IO_COUNTERS
{
public ulong ReadOperationCount;
public ulong WriteOperationCount;
public ulong OtherOperationCount;
public ulong ReadTransferCount;
public ulong WriteTransferCount;
public ulong OtherTransferCount;
}
[StructLayout(LayoutKind.Sequential)]
struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
{
public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
public IO_COUNTERS IoInfo;
public IntPtr ProcessMemoryLimit;
public IntPtr JobMemoryLimit;
public IntPtr PeakProcessMemoryUsed;
public IntPtr PeakJobMemoryUsed;
}
//
// Basic Limits
//
public const int JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001;
public const int JOB_OBJECT_LIMIT_PROCESS_TIME = 0x00000002;
public const int JOB_OBJECT_LIMIT_JOB_TIME = 0x00000004;
public const int JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 0x00000008;
public const int JOB_OBJECT_LIMIT_AFFINITY = 0x00000010;
public const int JOB_OBJECT_LIMIT_PRIORITY_CLASS = 0x00000020;
public const int JOB_OBJECT_LIMIT_PRESERVE_JOB_TIME = 0x00000040;
public const int JOB_OBJECT_LIMIT_SCHEDULING_CLASS = 0x00000080;
//
// Extended Limits
//
public const int JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_HIGH = JOB_OBJECT_LIMIT_JOB_MEMORY;
public const int JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION = 0x00000400;
public const int JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800;
public const int JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK = 0x00001000;
public const int JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
public const int JOB_OBJECT_LIMIT_SUBSET_AFFINITY = 0x00004000;
public const int JOB_OBJECT_LIMIT_JOB_MEMORY_LOW = 0x00008000;
public enum JOBOBJECTINFOCLASS
{
JobObjectBasicAccountingInformation = 1,
JobObjectBasicLimitInformation,
JobObjectBasicProcessIdList,
JobObjectBasicUIRestrictions,
JobObjectSecurityLimitInformation, // deprecated
JobObjectEndOfJobTimeInformation,
JobObjectAssociateCompletionPortInformation,
JobObjectBasicAndIoAccountingInformation,
JobObjectExtendedLimitInformation,
JobObjectJobSetInformation,
JobObjectGroupInformation,
JobObjectNotificationLimitInformation,
JobObjectLimitViolationInformation,
JobObjectGroupInformationEx,
JobObjectCpuRateControlInformation,
JobObjectCompletionFilter,
JobObjectCompletionCounter,
JobObjectReserved1Information = 18,
JobObjectReserved2Information,
JobObjectReserved3Information,
JobObjectReserved4Information,
JobObjectReserved5Information,
JobObjectReserved6Information,
JobObjectReserved7Information,
JobObjectReserved8Information,
JobObjectReserved9Information,
JobObjectReserved10Information,
JobObjectReserved11Information,
JobObjectReserved12Information,
JobObjectReserved13Information,
JobObjectReserved14Information = 31,
JobObjectNetRateControlInformation,
JobObjectNotificationLimitInformation2,
JobObjectLimitViolationInformation2,
JobObjectCreateSilo,
JobObjectSiloBasicInformation,
JobObjectReserved15Information = 37,
JobObjectReserved16Information,
JobObjectReserved17Information,
JobObjectReserved18Information,
JobObjectReserved19Information = 41,
JobObjectReserved20Information,
MaxJobObjectInfoClass
}
I think any of the ways you mentioned should work.
In addition, there is a matching feature in c#: Define an array with the fixed keyword:
struct JOBOBJECT_BASIC_PROCESS_ID_LIST
{
int NumberOfAssignedProcesses;
int NumberOfProcessIdsInList;
fixed IntPtr ProcessIdList[1];
}
See documentation:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/unsafe-code-pointers/fixed-size-buffers
Also no bounds check, so you should be able to read behind the end of the struckt easily:
Note
Except for memory created by using stackalloc, the C# compiler and the common language runtime (CLR) do not perform any security buffer overrun checks. As with all unsafe code, use caution.
I try to programmatically enumerate the DHCP filters on my Windows 2012 R2 DHCP server. Using P/Invoke, the code looks like:
public const uint ERROR_SUCCESS = 0;
public const uint ERROR_MORE_DATA = 234;
public const uint ERROR_NO_MORE_ITEMS = 259;
public const int MAX_PATTERN_LENGTH = 255;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_ADDR_PATTERN {
public bool MatchHWType;
public byte HWType;
public bool IsWildCard;
public byte Length;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_PATTERN_LENGTH)]
public byte[] Pattern;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_ENUM_INFO {
public uint NumElements;
public IntPtr pEnumRecords;
}
public enum DHCP_FILTER_LIST_TYPE : uint {
Deny = 0x1,
Allow = 0x2
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DHCP_FILTER_RECORD {
public DHCP_ADDR_PATTERN AddrPatt;
public string Comment;
}
[DllImport("dhcpsapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern uint DhcpEnumFilterV4(string ServerIpAddress,
ref DHCP_ADDR_PATTERN ResumeHandle, uint PreferredMaximum,
DHCP_FILTER_LIST_TYPE ListType, out IntPtr EnumFilterInfo,
out uint ElementsRead, out uint ElementsTotal);
public static IEnumerable<DHCP_FILTER_RECORD> DhcpEnumFilterV4(
string serverIpAddress, DHCP_FILTER_LIST_TYPE listType,
uint preferredMaximum = 1024) {
uint cntRead = 0;
uint cntTotal = 0;
uint error = ERROR_SUCCESS;
var hResume = new DHCP_ADDR_PATTERN();
var data = IntPtr.Zero;
var size = Marshal.SizeOf(typeof(DHCP_FILTER_RECORD));
do {
error = DhcpEnumFilterV4(serverIpAddress, ref hResume,
preferredMaximum, listType, out data, out cntRead,
out cntTotal);
//
// PROBLEM OCCURS HERE: 'error' is always 259
//
if ((error == ERROR_SUCCESS) || (error == ERROR_MORE_DATA)) {
var array = data.ToStructure<DHCP_FILTER_ENUM_INFO>();
for (uint i = 0; i < array.NumElements; ++i) {
var ptr = new IntPtr((long) array.pEnumRecords + i * size);
var obj = (DHCP_FILTER_RECORD) Marshal.PtrToStructure(ptr, typeof(DHCP_FILTER_RECORD));
yield return obj;
}
DhcpRpcFreeMemory(array.pEnumRecords);
DhcpRpcFreeMemory(data);
data = IntPtr.Zero;
} else if (error != ERROR_NO_MORE_ITEMS) {
Debug.Assert(data == IntPtr.Zero);
throw new Win32Exception((int) error);
}
} while (error == ERROR_MORE_DATA);
}
[DllImport("dhcpsapi.dll", SetLastError = true)]
public static extern void DhcpRpcFreeMemory(IntPtr BufferPointer);
The documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897526(v=vs.85).aspx) of the whole DHCP APIs is imho a bit sketchy, so I am not completely sure whether I am doing the right thing.
The problem is: I never get any results, DhcpEnumFilterV4 always returns ERROR_NO_MORE_ITEMS. Any suggestions?
I just stumbled over an important user comment regarding DHCP_FILTER_LIST_TYPE in MSDN (http://msdn.microsoft.com/en-us/library/windows/desktop/dd897586(v=vs.85).aspx). It seems that the definition of the enumeration in MSDN is wrong. The following
typedef enum {
Deny = 0x1, // This is wrong!
Allow = 0x2 // This is wrong!
} DHCP_FILTER_LIST_TYPE;
should be
typedef enum {
Deny = 0x0, // This is correct!
Allow = 0x1 // This is correct!
} DHCP_FILTER_LIST_TYPE;
Using the updated constants, my code works.
there are some similar questions to this on the net - even a few here, but even though the askers seem happy I can't find one that actually does what I need.
I'm trying to add a remote directory browsing feature to a web-based administration control panel (intranet based).
I don't need to worry about security at this point as this is handled elsewhere.
To do this I'm using a webservice which accepts a server name and a share/folder path as parameters. I just need it to return the subdirectories of this path, if any.
Doesn't sound so hard, does it? Well, it is (at least to me!)
The only bit I need help with is actually producing a list of directories for the server and path supplied.
All help is appreciated, but please don't just link to a site as I've probably seen it already but failed to get a working solution; most of these don't even seem to attempt to do what the title implies.
Some explaination would be helpful as well!
Cheers
To enumerate subfolders of specified folder in .NET you can use for example DirectoryInfo.EnumerateDirectories method.
To enumerate shares of some computer you can use WNetEnumResource native function if hidden administrative shares like C$, ADMIN$, print$ and so on are not important for you or use NetShareEnum to enumerate all shares.
The corresponding code could be
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;
namespace Subfolders {
static internal class Native {
[DllImport ("Netapi32.dll", SetLastError = true)]
internal static extern uint NetApiBufferFree (IntPtr buffer);
[DllImport ("Netapi32.dll", CharSet = CharSet.Unicode)]
internal static extern uint NetShareEnum (
string serverName,
int level,
ref IntPtr bufPtr,
uint prefmaxlen,
ref int entriesread,
ref int totalentries,
ref int resumeHandle
);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetEnumResource(IntPtr hEnum, ref int lpcCount, IntPtr lpBuffer, ref int lpBufferSize);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetOpenEnum(ResourceScope dwScope, ResourceType dwType, ResourceUsage dwUsage,
IntPtr lpNetResource, out IntPtr lphEnum);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetCloseEnum(IntPtr hEnum);
internal const uint MaxPreferredLength = 0xFFFFFFFF;
internal const int NerrSuccess = 0;
internal enum NetError : uint {
NerrSuccess = 0,
NerrBase = 2100,
NerrUnknownDevDir = (NerrBase + 16),
NerrDuplicateShare = (NerrBase + 18),
NerrBufTooSmall = (NerrBase + 23),
}
internal enum ShareType : uint {
StypeDisktree = 0,
StypePrintq = 1,
StypeDevice = 2,
StypeIpc = 3,
StypeSpecial = 0x80000000,
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ShareInfo1 {
public string shi1_netname;
public uint shi1_type;
public string shi1_remark;
public ShareInfo1 (string sharename, uint sharetype, string remark) {
shi1_netname = sharename;
shi1_type = sharetype;
shi1_remark = remark;
}
public override string ToString () {
return shi1_netname;
}
}
public enum ResourceScope: uint {
ResourceConnected = 0x00000001,
ResourceGlobalnet = 0x00000002,
ResourceRemembered = 0x00000003,
ResourceRecent = 0x00000004,
ResourceContext = 0x00000005
}
public enum ResourceType: uint {
ResourcetypeAny = 0x00000000,
ResourcetypeDisk = 0x00000001,
ResourcetypePrint = 0x00000002,
ResourcetypeReserved = 0x00000008,
ResourcetypeUnknown = 0xFFFFFFFF
}
public enum ResourceUsage: uint {
ResourceusageConnectable = 0x00000001,
ResourceusageContainer = 0x00000002,
ResourceusageNolocaldevice = 0x00000004,
ResourceusageSibling = 0x00000008,
ResourceusageAttached = 0x00000010,
ResourceusageAll = (ResourceusageConnectable | ResourceusageContainer | ResourceusageAttached),
ResourceusageReserved = 0x80000000
}
public enum ResourceDisplaytype: uint {
ResourcedisplaytypeGeneric = 0x00000000,
ResourcedisplaytypeDomain = 0x00000001,
ResourcedisplaytypeServer = 0x00000002,
ResourcedisplaytypeShare = 0x00000003,
ResourcedisplaytypeFile = 0x00000004,
ResourcedisplaytypeGroup = 0x00000005,
ResourcedisplaytypeNetwork = 0x00000006,
ResourcedisplaytypeRoot = 0x00000007,
ResourcedisplaytypeShareadmin = 0x00000008,
ResourcedisplaytypeDirectory = 0x00000009,
ResourcedisplaytypeTree = 0x0000000A,
ResourcedisplaytypeNdscontainer = 0x0000000B
}
[StructLayout (LayoutKind.Sequential)]
public struct NetResource {
public ResourceScope dwScope;
public ResourceType dwType;
public ResourceDisplaytype dwDisplayType;
public ResourceUsage dwUsage;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpLocalName;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpRemoteName;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpComment;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpProvider;
}
}
class Program {
static IEnumerable<string> GetShares(string computerName) {
var resources = new List<string>();
IntPtr hEnum = IntPtr.Zero, pResource = IntPtr.Zero;
try {
var resource = new Native.NetResource();
int bufferSize = 163840;
resource.dwType = Native.ResourceType.ResourcetypeAny;
resource.dwScope = Native.ResourceScope.ResourceGlobalnet;
resource.dwUsage = Native.ResourceUsage.ResourceusageContainer;
resource.lpRemoteName = computerName;
pResource = Marshal.AllocHGlobal(Marshal.SizeOf(resource));
Marshal.StructureToPtr (resource, pResource, false);
uint status = Native.WNetOpenEnum (Native.ResourceScope.ResourceGlobalnet,
Native.ResourceType.ResourcetypeDisk,
0,
pResource,
out hEnum);
if (status != 0)
return resources;
int numberOfEntries = -1;
IntPtr pBuffer = Marshal.AllocHGlobal(bufferSize);
status = Native.WNetEnumResource (hEnum, ref numberOfEntries, pBuffer, ref bufferSize);
if (status == Native.NerrSuccess && numberOfEntries > 0) {
var ptr = pBuffer;
for (int i = 0; i < numberOfEntries; i++, ptr += Marshal.SizeOf(resource)) {
resource = (Native.NetResource)Marshal.PtrToStructure (ptr, typeof (Native.NetResource));
resources.Add (resource.lpRemoteName.StartsWith (computerName + '\\',
StringComparison.OrdinalIgnoreCase)
? resource.lpRemoteName.Substring (computerName.Length + 1)
: resource.lpRemoteName);
}
}
} finally {
if (hEnum != IntPtr.Zero) {
Native.WNetCloseEnum (hEnum);
}
if (pResource != IntPtr.Zero) {
Marshal.FreeHGlobal(pResource);
}
}
return resources;
}
static IEnumerable<string> GetAllShares (string computerName) {
var shares = new List<string> ();
IntPtr bufPtr = IntPtr.Zero;
int entriesread = 0;
int totalentries = 0;
int resumeHandle = 0;
int nStructSize = Marshal.SizeOf (typeof (Native.ShareInfo1));
try {
uint ret = Native.NetShareEnum (computerName, 1, ref bufPtr,
Native.MaxPreferredLength,
ref entriesread,
ref totalentries,
ref resumeHandle);
if (ret == (uint)Native.NetError.NerrSuccess) {
var currentPtr = bufPtr;
for (int i = 0; i < entriesread; i++) {
var shi1 = (Native.ShareInfo1)Marshal.PtrToStructure (currentPtr, typeof (Native.ShareInfo1));
if ((shi1.shi1_type & ~(uint)Native.ShareType.StypeSpecial) == (uint)Native.ShareType.StypeDisktree) {
shares.Add (shi1.shi1_netname);
}
currentPtr = new IntPtr (currentPtr.ToInt32 () + nStructSize);
}
}
} finally {
if (bufPtr != IntPtr.Zero)
Native.NetApiBufferFree (bufPtr);
}
return shares;
}
static IEnumerable<string> GetSubdirectories (string root) {
var dirInfo = new DirectoryInfo (root);
return (from info in dirInfo.EnumerateDirectories () select info.Name).ToList();
}
static void Main () {
var root = #"\\OK01\Users";
Console.WriteLine ("Subdirectories of {0}:", root);
foreach (var dir in GetSubdirectories (root)) {
Console.WriteLine (dir);
}
Console.WriteLine ();
root = #"\\OK01\Users\Public";
Console.WriteLine ("Subdirectories of {0}:", root);
foreach (var dir in GetSubdirectories (root)) {
Console.WriteLine (dir);
}
Console.WriteLine ();
root = #"\\OK01";
Console.WriteLine ("All Shares of {0} (inclusive hidden):", root);
foreach (var shareName in GetAllShares (root)) {
Console.WriteLine (shareName);
}
Console.WriteLine ();
root = #"\\OK01";
Console.WriteLine ("Shares of {0}:", root);
foreach (var shareName in GetShares (root)) {
Console.WriteLine (shareName);
}
}
}
}
which produce output like
Subdirectories of \\OK01\Users:
All Users
ASP.NET v4.0
Default
Default User
MSSQL$SQL2012
Oleg
Public
Subdirectories of \\OK01\Users\Public:
Desktop
Documents
Downloads
Favorites
Libraries
Music
Pictures
Recorded TV
Roaming
Videos
All Shares of \\OK01 (inclusive hidden):
ADMIN$
C$
print$
Q$
Users
Virtual Machines
VMware
Shares of \\OK01:
Users
Virtual Machines
VMware
The above code is simplified to demonstrate only how to use the corresponding API. It contains no real error reporting.
You can use method described here using Interop.
I made a few modifications to the code to come up with this. I have not extensively tested this, so it may have errors but it should get you started.
private List<string> GetSubDirectories(string serverName, string folderPath)
{
List<string> subDirectories = new List<string>();
string folder_path = Path.Combine(serverName, folderPath);
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData;
IntPtr findHandle;
findHandle = FindFirstFile(folder_path, out findData);
if (findHandle == INVALID_HANDLE_VALUE)
{
int error = Marshal.GetLastWin32Error();
Console.WriteLine(error.ToString());
return null;
}
do
{
try
{
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
subDirectories.Add(findData.cFileName);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
return subDirectories;
}
public const int FILE_ATTRIBUTE_DIRECTORY = 0x10;
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FindClose(IntPtr hFindFile);
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
}
You can call it like:
var subdirectories = GetSubDirectories(#"\\[serverName]", #"[folderPath]\*");
You have to add "\*" as per MSDN
On network shares, you can use an lpFileName in the form of the
following: "\Server\Share*". However, you cannot use an lpFileName
that points to the share itself; for example, "\Server\Share" is not
valid.
Not sure if we can achieve this. We had similar problem but finally resolved it by providing the shared path (\SERVERNAME\FOLDER).
Most important webservice should use a account that has full permission to access the directory else exception related to permission will be thrown out to calling client.
Well, actually it can be done using NetShareEnum Win32API function.
But here is .NET wrapper classes to enumerate network shares on local and remote machines, and convert local file paths to UNC paths. Please see the article Network Shares and UNC paths.
I am writing a C# .NET app that accesses an USB device which exposes a serial port interface. I am using the handy .NET SerialPort class, which works just fine.
My problem is that I need to catch the DBT_DEVICEQUERYREMOVE event, but I don't get the event if I register using DBT_DEVTYP_DEVICEINTERFACE. I do get DBT_DEVICEARRIVAL and DBT_DEVICEREMOVECOMPLETE, but no DBT_DEVICEQUERYREMOVE.
From my web research it seems that I need to register using DBT_DEVTYP_HANDLE, which requires a handle, such as that returned by CreateFile. Since the SerialPort class does not expose this handle, I'm wondering if there is some other way to get the handle (or some other way to get the event of interest).
I think you could use a bit of reflection to get the handle, I don't know of a better way to get the handle that the .NET Framework is currently using. The SerialPort uses an internal type called SerialStream. This Stream has the handle you want. Since I don't have a serial port to test on, this code is a bit of a guesswork:
var serialPort = new SerialPort();
object stream = typeof(SerialPort).GetField("internalSerialStream", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(serialPort);
var handle = (SafeFileHandle)stream.GetType().GetField("_handle", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(stream);
This will give you a SafeFileHandle, which is a wrapper for handles. You could call DangerousGetHandle to get the actual IntPtr.
This handle only has a valid value after you call Open on the SerialPort, and becomes invalid when it's disposed. You should check the IsInvalid and IsClosed values of the handle first before using DangerousGetHandle.
What is also a solution is to grab the Serialport implementation of .Net and change it to your liking.
This is what I did for a project where I needed access to the handle, and because I had timing/async issues with SerialPort. So I boiled it down to the bear necessities.
public class SimpleSerialPort : IDisposable
{
private const uint GenericRead = 0x80000000;
private const uint GenericWrite = 0x40000000;
private const int OpenExisting = 3;
private const uint Setdtr = 5; // Set DTR high
private FileStream _fileStream;
public void Close()
{
Dispose();
}
public int WriteTimeout { get; set; }
public SafeFileHandle Handle { get; private set; }
public void Open(string portName, uint baudrate)
{
// Check if port can be found
bool isValid =
SerialPort.GetPortNames()
.Any(x => String.Compare(x, portName, StringComparison.OrdinalIgnoreCase) == 0);
if (!isValid)
{
throw new IOException(string.Format("{0} port was not found", portName));
}
string port = #"\\.\" + portName;
Handle = CreateFile(port, GenericRead | GenericWrite, 0, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero);
if (Handle.IsInvalid)
{
throw new IOException(string.Format("{0} port is already open", portName));
}
var dcb = new Dcb();
// first get the current dcb structure setup
if (GetCommState(Handle, ref dcb) == false)
{
throw new IOException(string.Format("GetCommState error {0}", portName));
}
dcb.BaudRate = baudrate;
dcb.ByteSize = 8;
dcb.Flags = 129;
dcb.XoffChar = 0;
dcb.XonChar = 0;
/* Apply the settings */
if (SetCommState(Handle, ref dcb) == false)
{
throw new IOException(string.Format("SetCommState error {0}", portName));
}
/* Set DTR, some boards needs a DTR = 1 level */
if (EscapeCommFunction(Handle, Setdtr) == false)
{
throw new IOException(string.Format("EscapeCommFunction error {0}", portName));
}
// Write default timeouts
var cto = new Commtimeouts
{
ReadTotalTimeoutConstant = 500,
ReadTotalTimeoutMultiplier = 0,
ReadIntervalTimeout = 10,
WriteTotalTimeoutConstant = WriteTimeout,
WriteTotalTimeoutMultiplier = 0
};
if (SetCommTimeouts(Handle, ref cto) == false)
{
throw new IOException(string.Format("SetCommTimeouts error {0}", portName));
}
// Create filestream
_fileStream = new FileStream(Handle, FileAccess.ReadWrite, 32, false);
}
public void Write(byte[] bytes)
{
_fileStream.Write(bytes, 0, bytes.Length);
}
public void Read(byte[] readArray)
{
for (int read = 0; read < readArray.Length;)
{
read += _fileStream.Read(readArray, read, readArray.Length - read);
}
}
public byte ReadByte()
{
byte[] readsBytes = new byte[1];
Read(readsBytes);
return readsBytes[0];
}
public void Dispose()
{
if (Handle != null)
{
Handle.Dispose();
}
if (_fileStream != null)
{
_fileStream.Dispose();
}
_fileStream = null;
Handle = null;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode,
IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool GetCommState(
SafeFileHandle hFile, // handle to communications device
ref Dcb lpDcb // device-control block
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetCommState(
SafeFileHandle hFile, // handle to communications device
ref Dcb lpDcb // device-control block
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool EscapeCommFunction(
SafeFileHandle hFile, // handle to communications device
uint dwFunc
);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool SetCommTimeouts(
SafeFileHandle hFile, // handle to comm device
ref Commtimeouts lpCommTimeouts // time-out values
);
[StructLayout(LayoutKind.Sequential)]
private struct Commtimeouts
{
public int ReadIntervalTimeout;
public int ReadTotalTimeoutMultiplier;
public int ReadTotalTimeoutConstant;
public int WriteTotalTimeoutMultiplier;
public int WriteTotalTimeoutConstant;
}
[StructLayout(LayoutKind.Sequential)]
private struct Dcb
{
private readonly uint DCBlength;
public uint BaudRate;
public uint Flags;
private readonly ushort WReserved;
private readonly ushort XonLim;
private readonly ushort XoffLim;
public byte ByteSize;
private readonly byte Parity;
private readonly byte StopBits;
public byte XonChar;
public byte XoffChar;
private readonly byte ErrorChar;
private readonly byte EofChar;
private readonly byte EvtChar;
private readonly ushort WReserved1;
}
}