I have the keen idea to write a wrapper for Vulkan in c#.
Unfortunately the second call of the Vulkan API already fails unexplainably.
The code below is taken from Sascha Willems' Vulkan examples and converted into c# code:
Vk.ApplicationInfo applicationInfo = new Vk.ApplicationInfo();
applicationInfo.sType = Vk.StructureType.STRUCTURE_TYPE_APPLICATION_INFO;
applicationInfo.pApplicationName = "Example";
applicationInfo.pEngineName = "Example";
applicationInfo.apiVersion = (uint)Math.Pow(2, 22) + 2;
string[] enabledExtensions = new string[] { "VK_KHR_surface", "VK_KHR_win32_surface" };
Vk.InstanceCreateInfo instanceCreateInfo = new Vk.InstanceCreateInfo();
instanceCreateInfo.sType = Vk.StructureType.STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instanceCreateInfo.pNext = null;
instanceCreateInfo.pApplicationInfo = applicationInfo;
instanceCreateInfo.enabledExtensionCount = (uint)enabledExtensions.Count();
instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions;
Vk.Instance theInstance = new Vk.Instance();
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, theInstance);
// vr = SUCCESS
uint gpuCount = 0;
vr = Vk.vkEnumeratePhysicalDevices(theInstance, ref gpuCount, IntPtr.Zero);
//Fails with System.AccessViolationException
with
public static class Vk
{
public enum Result
{
SUCCESS = 0,
...
};
public enum StructureType
{
...
}
static Vk()
{
List<string> path = new List<string>() { #"C:\VulkanSDK\1.0.3.1\Source\lib32\" };
AddEnvironmentPaths(path);
}
static void AddEnvironmentPaths(IEnumerable<string> paths)
{
var path = new[] { Environment.GetEnvironmentVariable("PATH") ?? string.Empty };
string newPath = string.Join(Path.PathSeparator.ToString(), path.Concat(paths));
Environment.SetEnvironmentVariable("PATH", newPath);
}
[DllImport("vulkan-1.dll")]
public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, Instance instance);
[StructLayout(LayoutKind.Sequential)]
public class InstanceCreateInfo
{
public StructureType sType;
public object pNext;
public uint flags;
public ApplicationInfo pApplicationInfo;
public uint enabledLayerCount;
public string[] ppEnabledLayerNames;
public uint enabledExtensionCount;
public string[] ppEnabledExtensionNames;
}
[StructLayout(LayoutKind.Sequential)]
public class ApplicationInfo
{
public StructureType sType;
public object pNext;
public string pApplicationName;
public uint applicationVersion;
public string pEngineName;
public uint engineVersion;
public uint apiVersion;
}
[StructLayout(LayoutKind.Sequential)]
public class Instance
{
}
[DllImport("vulkan-1.dll")]
public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, PhysicalDevice pPhysicalDevices);
[DllImport("vulkan-1.dll")]
public static extern Result vkEnumeratePhysicalDevices(Instance instance, ref uint pPhysicalDeviceCount, IntPtr pPhysicalDevices);
public class PhysicalDevice
{
}
}
My Suspicion is that Vk.Instance should be something else than just an empty class. VkInstance is in the official vulkan.h defined as typedef struct VkInstance_T* VkInstance. My understanding of this line is unfortunately very limited. I already tried exchanging the type Vk.Instance with IntPtr and object but without success.
Theses are important segments from vulkan.h
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
VK_DEFINE_HANDLE(VkPhysicalDevice)
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
VkInstance instance,
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices);
Zastai answered my question.
It had to be
[DllImport("vulkan-1.dll")]
public static extern Result vkCreateInstance(InstanceCreateInfo instanceCreateInfo, IntPtr pAllocator, out IntPtr instance);
because it were indeed pointers to pointers.
IntPtr instance;
Vk.Result vr = Vk.vkCreateInstance(instanceCreateInfo, IntPtr.Zero, out instance);
uint gpuCount = 0;
vr = Vk.vkEnumeratePhysicalDevices(instance, ref gpuCount, IntPtr.Zero);
Thanks a lot!
Related
I'm trying to create a Vulkan wrapper in C#, but I have some problems when I call a function. I rewrote the vulkan.h header as follows :
public static class Vk {
[StructLayout(LayoutKind.Sequential)] public class Instance { }
public enum Result {
...
}
public enum StructureType {
...
}
[StructLayout(LayoutKind.Sequential)] public class ApplicationInfo {
public StructureType sType;
public IntPtr pNext;
public string pApplicationName;
public uint applicationVersion;
public string pEngineName;
public uint engineVersion;
public uint apiVersion;
}
[StructLayout(LayoutKind.Sequential)] public class InstanceCreateInfo {
public StructureType sType;
public IntPtr pNext;
public uint flags_VkInstanceCreateFlags;
public ApplicationInfo pApplicationInfo;
public uint enabledLayerCount;
public string[] ppEnabledLayerNames;
public uint enabledExtensionCount;
public string[] ppEnabledExtensionNames;
}
[DllImport("vulkan-1.dll", EntryPoint = "vkCreateInstance")]
public extern static Result CreateInstance(
InstanceCreateInfo pCreateInfo,
IntPtr AllocationCallbacks_pAllocator,
out IntPtr pInstance_Instance);
}
The original declaration in C of this function is
VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
Now when I call my function, I'm doing like this :
Vk.InstanceCreateInfo instance_create_info = new Vk.InstanceCreateInfo();
...
IntPtr hinstance;
Vk.Result result = Vk.CreateInstance(instance_create_info, IntPtr.Zero, out hinstance); <-- error AccessViolationException
I don't understand where is my problem, because it seems to be a valid solution : StackOverflow : AccessViolationException when calling vkEnumeratePhysicalDevices via pInvoke from c#.
I tried by initializing my IntPtr hinstance with
Marshal.AllocHGlobal(Marshal.SizeOf<Vk.Instance>());
I also tried to "convert" my instance_create_info to another IntPtr with Marshal.StructureToPtr(...); and I tried to pass instance_create_info and instance by the ref keyword. Obviously, nothing worked.
Any idea ?
EDIT :
The native function is used as follows :
//Definition
typedef struct VkApplicationInfo {
VkStructureType sType;
const void* pNext;
const char* pApplicationName;
uint32_t applicationVersion;
const char* pEngineName;
uint32_t engineVersion;
uint32_t apiVersion;
} VkApplicationInfo;`
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object;
VK_DEFINE_HANDLE(VkInstance)
//Code
VkApplicationInfo application_info{};
application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
application_info.apiVersion = VK_API_VERSION;
application_info.applicationVersion = VK_MAKE_VERSION( 1, 0, 0 );
application_info.pApplicationName = "";
application_info.engineVersion = VK_MAKE_VERSION( 1, 0, 0 );
application_info.pEngineName = "";
VkInstanceCreateInfo instance_create_info{};
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
instance_create_info.pApplicationInfo = &application_info;
instance_create_info.enabledLayerCount = 0
instance_create_info.ppEnabledLayerNames = nullptr
instance_create_info.enabledExtensionCount = 0
instance_create_info.ppEnabledExtensionNames = nullptr
VkInstance _instance = nullptr;
assert( !vkCreateInstance( &instance_create_info, nullptr, &_instance ) );
it seems that you are trying to do something similar this guy made a wrapper for the c#. Can be useful for you. Go to Source/SharpVulkan/Generated/Functions.
public static unsafe Instance CreateInstance(ref InstanceCreateInfo createInfo, AllocationCallbacks* allocator = null)
{
Instance instance;
fixed (InstanceCreateInfo* __createInfo__ = &createInfo)
{
vkCreateInstance(__createInfo__, allocator, &instance).CheckError();
}
return instance;
}
[DllImport("vulkan-1.dll", CallingConvention = CallingConvention.StdCall)]
internal static extern unsafe Result vkCreateInstance(InstanceCreateInfo* createInfo, AllocationCallbacks* allocator, Instance* instance);
internal static unsafe void EnumerateInstanceExtensionProperties(byte* layerName, ref uint propertyCount, ExtensionProperties* properties)
{
fixed (uint* __propertyCount__ = &propertyCount)
{
vkEnumerateInstanceExtensionProperties(layerName, __propertyCount__, properties).CheckError();
}
}
Hope it is helpfull :)
remove out keyword for third argument or declare it as corresponding struct.
I'm trying to use CryptoAPI from C# code to add SHA256 timestamps to signed assemblies. Here is the code I'm using:
Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com");
Signer class:
public static class Signer
{
[StructLayoutAttribute(LayoutKind.Sequential)]
struct SIGNER_SUBJECT_INFO
{
public uint cbSize;
public IntPtr pdwIndex;
public uint dwSubjectChoice;
public SubjectChoiceUnion Union1;
[StructLayoutAttribute(LayoutKind.Explicit)]
internal struct SubjectChoiceUnion
{
[FieldOffsetAttribute(0)]
public IntPtr pSignerFileInfo;
[FieldOffsetAttribute(0)]
public IntPtr pSignerBlobInfo;
}
}
[StructLayoutAttribute(LayoutKind.Sequential)]
struct SIGNER_FILE_INFO
{
public uint cbSize;
public IntPtr pwszFileName;
public IntPtr hFile;
}
[DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int SignerTimeStampEx2(
uint dwFlags, // DWORD
IntPtr pSubjectInfo, // SIGNER_SUBJECT_INFO
string pwszHttpTimeStamp, // LPCWSTR
uint dwAlgId, // ALG_ID
IntPtr psRequest, // PCRYPT_ATTRIBUTES
IntPtr pSipData, // LPVOID
out IntPtr ppSignerContext // SIGNER_CONTEXT
);
public static void TimestampSignedAssembly(string appPath, string tsaServer)
{
if (tsaServer == null) throw new ArgumentNullException("tsaServer");
var pSubjectInfo = IntPtr.Zero;
try
{
pSubjectInfo = CreateSignerSubjectInfo(appPath);
TimestampSignedAssembly(pSubjectInfo, tsaServer);
}
finally
{
if (pSubjectInfo != IntPtr.Zero)
{
Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO));
}
}
}
private static IntPtr CreateSignerSubjectInfo(string pathToAssembly)
{
var info = new SIGNER_SUBJECT_INFO
{
cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
};
var index = 0;
Marshal.StructureToPtr(index, info.pdwIndex, false);
info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE
var assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly);
var fileInfo = new SIGNER_FILE_INFO
{
cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)),
pwszFileName = assemblyFilePtr,
hFile = IntPtr.Zero
};
info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion
{
pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO)))
};
Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false);
IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, pSubjectInfo, false);
return pSubjectInfo;
}
/*
Here CryptoAPI function SignerTimeStampEx2 called.
*/
private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer)
{
IntPtr context;
var hResult = SignerTimeStampEx2(
0x1, // I have not found anywhere what value should have this parameter!
pSubjectInfo,
tsaServer,
0x0000800c, // 256 bit SHA hashing algorithm. This value taken form here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
IntPtr.Zero,
IntPtr.Zero,
out context
);
if (hResult != 0)
{
throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult));
}
}
}
Despite the fact that I pass to SignerTimeStampEx2 function an argument (dwAlgId), indicating that it is necessary to add SHA256 timestamp (0x0000800c), SHA1 timestamp is always generated.
Has anyone encountered with this problem? What I'm doing wrong? What values should I set for dwFlags and dwAlgId parameters?
Thanks in advance!
dwFlags needs to be SIGNER_TIMESTAMP_RFC3161 (2). The reason you get an access violation is that SignerTimeStampEx2() is documented incorrectly. It expects the algorithm as a PCSTR rather than a DWORD. If you pass 0x800C it'll try to dereference that as a pointer, leading to the AV. So replace ALG_ID dwAlgId in the function declaration with PCSTR pszTimeStampAlgorithmOid. Pass szOID_NIST_sha256 to it, which should be defined as "2.16.840.1.101.3.4.2.1".
SignerTimeStampEx3() is also incorrectly incorrectly documented. pszTimeStampAlgorithmOid should be declared as PCSTR rather than as PCWSTR.
In my experience, code signing and time stamping are more reliable if you specify both the file name and an open Win32 file handle in the SIGNER_FILE_INFO structure.
Whether you will actually get an SHA-256 time stamp also depends on the time stamping service you're using. http://tsa.starfieldtech.com, http://timestamp.globalsign.com/ and http://timestamp.comodoca.com/rfc3161 issue SHA-256 timestamps. Other services may issue SHA-1 time stamps even when requesting an SHA-256 time stamp.
I got it working finally. Here is the complete code of the Timestamper class:
public static class Timestamper
{
[StructLayout(LayoutKind.Sequential)]
struct SIGNER_SUBJECT_INFO
{
public uint cbSize;
public IntPtr pdwIndex;
public uint dwSubjectChoice;
public SubjectChoiceUnion Union1;
[StructLayoutAttribute(LayoutKind.Explicit)]
internal struct SubjectChoiceUnion
{
[FieldOffsetAttribute(0)]
public IntPtr pSignerFileInfo;
[FieldOffsetAttribute(0)]
public IntPtr pSignerBlobInfo;
}
}
[StructLayoutAttribute(LayoutKind.Sequential)]
struct SIGNER_FILE_INFO
{
public uint cbSize;
public IntPtr pwszFileName;
public IntPtr hFile;
}
[DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int SignerTimeStampEx2(
uint dwFlags, // DWORD
IntPtr pSubjectInfo, // SIGNER_SUBJECT_INFO
string pwszHttpTimeStamp, // LPCWSTR
IntPtr pszTimeStampAlgorithmOid, // PCSTR
IntPtr psRequest, // PCRYPT_ATTRIBUTES
IntPtr pSipData, // LPVOID
out IntPtr ppSignerContext // SIGNER_CONTEXT
);
public static void TimestampSignedAssembly(string appPath, string tsaServer)
{
if (tsaServer == null) throw new ArgumentNullException("tsaServer");
IntPtr pSubjectInfo = IntPtr.Zero;
try
{
pSubjectInfo = CreateSignerSubjectInfo(appPath);
TimestampSignedAssembly(pSubjectInfo, tsaServer);
}
finally
{
if (pSubjectInfo != IntPtr.Zero)
{
Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO));
}
}
}
private static IntPtr CreateSignerSubjectInfo(string pathToAssembly)
{
SIGNER_SUBJECT_INFO info = new SIGNER_SUBJECT_INFO
{
cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)),
pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)))
};
int index = 0;
Marshal.StructureToPtr(index, info.pdwIndex, false);
info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE
IntPtr assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly);
SIGNER_FILE_INFO fileInfo = new SIGNER_FILE_INFO
{
cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)),
pwszFileName = assemblyFilePtr,
hFile = IntPtr.Zero
};
info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion
{
pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO)))
};
Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false);
IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info));
Marshal.StructureToPtr(info, pSubjectInfo, false);
return pSubjectInfo;
}
/*
Here CryptoAPI function SignerTimeStampEx2 called.
*/
private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer)
{
IntPtr context;
int hResult = SignerTimeStampEx2(
0x2, // SIGNER_TIMESTAMP_RFC3161
pSubjectInfo,
tsaServer,
Marshal.StringToHGlobalAnsi("2.16.840.1.101.3.4.2.1"), // szOID_NIST_sha256 constant, SHA256 hashing algorithm.
IntPtr.Zero,
IntPtr.Zero,
out context
);
if (hResult != 0)
{
throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult));
}
}
}
Usage example:
Timestamper.TimestampSignedAssembly("Assembly.exe", "http://timestamp.comodoca.com/?td=sha256");
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.
In my application I need to verify whether it's signed or not. If it's signed continue the execution and exit the application if not. The signtool will be used to sign the application.
Is there any C# code to do that?
Here is a utility method that does it:
var signed = IsSigned(#"c:\windows\explorer.exe");
...
public static bool IsSigned(string filePath)
{
if (filePath == null)
throw new ArgumentNullException(nameof(filePath));
var file = new WINTRUST_FILE_INFO();
file.cbStruct = Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));
file.pcwszFilePath = filePath;
var data = new WINTRUST_DATA();
data.cbStruct = Marshal.SizeOf(typeof(WINTRUST_DATA));
data.dwUIChoice = WTD_UI_NONE;
data.dwUnionChoice = WTD_CHOICE_FILE;
data.fdwRevocationChecks = WTD_REVOKE_NONE;
data.pFile = Marshal.AllocHGlobal(file.cbStruct);
Marshal.StructureToPtr(file, data.pFile, false);
int hr;
try
{
hr = WinVerifyTrust(INVALID_HANDLE_VALUE, WINTRUST_ACTION_GENERIC_VERIFY_V2, ref data);
}
finally
{
Marshal.FreeHGlobal(data.pFile);
}
return hr == 0;
}
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct WINTRUST_FILE_INFO
{
public int cbStruct;
public string pcwszFilePath;
public IntPtr hFile;
public IntPtr pgKnownSubject;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
private struct WINTRUST_DATA
{
public int cbStruct;
public IntPtr pPolicyCallbackData;
public IntPtr pSIPClientData;
public int dwUIChoice;
public int fdwRevocationChecks;
public int dwUnionChoice;
public IntPtr pFile;
public int dwStateAction;
public IntPtr hWVTStateData;
public IntPtr pwszURLReference;
public int dwProvFlags;
public int dwUIContext;
public IntPtr pSignatureSettings;
}
private const int WTD_UI_NONE = 2;
private const int WTD_REVOKE_NONE = 0;
private const int WTD_CHOICE_FILE = 1;
private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
private static readonly Guid WINTRUST_ACTION_GENERIC_VERIFY_V2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
[DllImport("wintrust.dll")]
private static extern int WinVerifyTrust(IntPtr hwnd, [MarshalAs(UnmanagedType.LPStruct)] Guid pgActionID, ref WINTRUST_DATA pWVTData);
Try
Dim objCertificate As New Security.Cryptography.X509Certificates.X509Certificate2(Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile(strFile))
Return True
Catch ex As Exception
Return False
End Try
private bool IsAssemblySigned()
{
var assembly = Assembly.GetAssembly(GetType());
var assemblyName = assembly.GetName();
var key = assemblyName.GetPublicKey();
return key.Length > 0;
}
I would suggest you use the 'CryptUIWizDigitalSign' API. This link can be used as a reference.
I've been using Mapi32 from a Winforms app to send bring up a new mail message with attachments for a while now, and it's worked really well. (Yes, I'm aware that calling into MAPI32 from C# is not supported.)
Within the last few days, it has stopped working when Outlook is running. However, if Outlook is not running, it will work as expected. This happens in both Vista and XP.
Have any SOer's had this problem? How did you resolve it?
Here's the code I've been using:
public class EmailController
{
[DllImport("MAPI32.DLL", CharSet = CharSet.Ansi)]
public static extern int MAPISendMail(IntPtr lhSession, IntPtr ulUIParam,
MapiMessage lpMessage, int flFlags, int ulReserved);
public const int MAPI_LOGON_UI = 0x00000001;
private const int MAPI_DIALOG = 0x00000008;
public static int SendMail(string strAttachmentFileName, string strSubject,string to)
{
IntPtr session = new IntPtr(0);
IntPtr winhandle = new IntPtr(0);
MapiMessage msg = new MapiMessage();
msg.subject = strSubject;
int sizeofMapiDesc = Marshal.SizeOf(typeof(MapiFileDesc));
IntPtr pMapiDesc = Marshal.AllocHGlobal(sizeofMapiDesc);
MapiFileDesc fileDesc = new MapiFileDesc();
fileDesc.position = -1;
int ptr = (int)pMapiDesc;
string path = strAttachmentFileName;
fileDesc.name = Path.GetFileName(path);
fileDesc.path = path;
Marshal.StructureToPtr(fileDesc, (IntPtr)ptr, false);
msg.files = pMapiDesc;
msg.fileCount = 1;
List<MapiRecipDesc> recipsList = new List<MapiRecipDesc>();
MapiRecipDesc recipient = new MapiRecipDesc();
recipient.recipClass = 1;
recipient.name = to;
recipsList.Add(recipient);
int size = Marshal.SizeOf(typeof(MapiRecipDesc));
IntPtr intPtr = Marshal.AllocHGlobal(recipsList.Count * size);
int recipPtr = (int)intPtr;
foreach (MapiRecipDesc mapiDesc in recipsList)
{
Marshal.StructureToPtr(mapiDesc, (IntPtr)recipPtr, false);
recipPtr += size;
}
msg.recips = intPtr;
msg.recipCount = 1;
int result = MAPISendMail(session, winhandle, msg, MAPI_LOGON_UI | MAPI_DIALOG, 0);
return result;
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiMessage
{
public int reserved;
public string subject;
public string noteText;
public string messageType;
public string dateReceived;
public string conversationID;
public int flags;
public IntPtr originator;
public int recipCount;
public IntPtr recips;
public int fileCount;
public IntPtr files;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiFileDesc
{
public int reserved;
public int flags;
public int position;
public string path;
public string name;
public IntPtr type;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MapiRecipDesc
{
public int reserved;
public int recipClass;
public string name;
public string address;
public int eIDSize;
public IntPtr entryID;
}
If you're application is running with Elevated Privileges (i.e. as Administrator) and Outlook isn't, the send will fail. You will have to tell the user to close all running instances of Outlook and try again.
int result = MAPISendMail(session, winhandle, msg, MAPI_LOGON_UI | MAPI_DIALOG, 0);
return result;
What does it return?
Well, other than the obvious "use supported C# mail-sending methods" comment, I wonder if something happened to the mapi32.dll file - have you tried a "Detect and Repair" in Outlook?
I also read here (http://office.microsoft.com/en-us/outlook/HP011164781033.aspx) that there are some steps you can do (the post and the comments) to get Outlook to repair or replace the dll.