I have recently bought a RFID R/W device, and I would like to send and receive data from it to a VBA application that I have already developed. I have been looking for a solution, but I was not able to find any.
I would like to know if there are any VBA instructions for receiving and sending data to a HID. If not, which would be the simplest way to communicate with my device? The code would be very simple, just writing and reading hex code. I could manage an application in vb or C# too.
The driver has been correctly installed and their specs. are in the link: http://www.securakey.com/PRODUCTS/RFID_PRODUCTS/ET4AUS_D_AUM_7656.pdf
Thank you all.
It's been a long time since I've done VBA programming but you will be able to use the same Windows API calls that C# or VB.Net use. Here is some example code for enumerating Hid devices and connecting. You will need to translate to VBA. This is a link on Windows API in VBA https://riptutorial.com/vba/example/31727/windows-api---dedicated-module--1-of-2-.
Here is Windows API code for enumerating Hid devices:
https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Device.Net/Windows/WindowsDeviceFactoryBase.cs
var deviceDefinitions = new Collection<DeviceDefinition>();
var spDeviceInterfaceData = new SpDeviceInterfaceData();
var spDeviceInfoData = new SpDeviceInfoData();
var spDeviceInterfaceDetailData = new SpDeviceInterfaceDetailData();
spDeviceInterfaceData.CbSize = (uint)Marshal.SizeOf(spDeviceInterfaceData);
spDeviceInfoData.CbSize = (uint)Marshal.SizeOf(spDeviceInfoData);
var guidString = ClassGuid.ToString();
var copyOfClassGuid = new Guid(guidString);
var i = APICalls.SetupDiGetClassDevs(ref copyOfClassGuid, IntPtr.Zero, IntPtr.Zero, APICalls.DigcfDeviceinterface | APICalls.DigcfPresent);
if (IntPtr.Size == 8)
{
spDeviceInterfaceDetailData.CbSize = 8;
}
else
{
spDeviceInterfaceDetailData.CbSize = 4 + Marshal.SystemDefaultCharSize;
}
var x = -1;
while (true)
{
x++;
var isSuccess = APICalls.SetupDiEnumDeviceInterfaces(i, IntPtr.Zero, ref copyOfClassGuid, (uint)x, ref spDeviceInterfaceData);
if (!isSuccess)
{
var errorCode = Marshal.GetLastWin32Error();
if (errorCode == APICalls.ERROR_NO_MORE_ITEMS)
{
break;
}
throw new Exception($"Could not enumerate devices. Error code: {errorCode}");
}
isSuccess = APICalls.SetupDiGetDeviceInterfaceDetail(i, ref spDeviceInterfaceData, ref spDeviceInterfaceDetailData, 256, out _, ref spDeviceInfoData);
WindowsDeviceBase.HandleError(isSuccess, "Could not get device interface detail");
//Note this is a bit nasty but we can filter Vid and Pid this way I think...
var vendorHex = vendorId?.ToString("X").ToLower().PadLeft(4, '0');
var productIdHex = productId?.ToString("X").ToLower().PadLeft(4, '0');
if (vendorId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(vendorHex)) continue;
if (productId.HasValue && !spDeviceInterfaceDetailData.DevicePath.ToLower().Contains(productIdHex)) continue;
var deviceDefinition = GetDeviceDefinition(spDeviceInterfaceDetailData.DevicePath);
deviceDefinitions.Add(deviceDefinition);
}
APICalls.SetupDiDestroyDeviceInfoList(i);
return deviceDefinitions;
Here is connection code:
public bool Initialize()
{
Dispose();
if (DeviceInformation == null)
{
throw new WindowsHidException($"{nameof(DeviceInformation)} must be specified before {nameof(Initialize)} can be called.");
}
var pointerToPreParsedData = new IntPtr();
_HidCollectionCapabilities = new HidCollectionCapabilities();
var pointerToBuffer = Marshal.AllocHGlobal(126);
_ReadSafeFileHandle = APICalls.CreateFile(DeviceInformation.DeviceId, APICalls.GenericRead | APICalls.GenericWrite, APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, 0, IntPtr.Zero);
_WriteSafeFileHandle = APICalls.CreateFile(DeviceInformation.DeviceId, APICalls.GenericRead | APICalls.GenericWrite, APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, 0, IntPtr.Zero);
if (!HidAPICalls.HidD_GetPreparsedData(_ReadSafeFileHandle, ref pointerToPreParsedData))
{
throw new Exception("Could not get pre parsed data");
}
var getCapsResult = HidAPICalls.HidP_GetCaps(pointerToPreParsedData, ref _HidCollectionCapabilities);
//TODO: Deal with issues here
Marshal.FreeHGlobal(pointerToBuffer);
var preparsedDataResult = HidAPICalls.HidD_FreePreparsedData(ref pointerToPreParsedData);
//TODO: Deal with issues here
if (_ReadSafeFileHandle.IsInvalid)
{
return false;
}
_ReadFileStream = new FileStream(_ReadSafeFileHandle, FileAccess.ReadWrite, _HidCollectionCapabilities.OutputReportByteLength, false);
_WriteFileStream = new FileStream(_WriteSafeFileHandle, FileAccess.ReadWrite, _HidCollectionCapabilities.InputReportByteLength, false);
IsInitialized = true;
RaiseConnected();
return true;
}
Related
I wrote this code to perform a shell style file drag operation from my wpf application to windows explorer:
private void OnMouseDown(object sender, MouseButtonEventArgs e)
{
DependencyObject src = (DependencyObject)(e.OriginalSource);
while (!(src is Control))
{
src = VisualTreeHelper.GetParent(src);
}
string clicked_element_name = src.GetType().Name;
if (clicked_element_name != "ListViewItem")
{
this.ExListView.UnselectAll();
this.ExListView.Focus();
}
else
{
ListViewItem item = src as ListViewItem;
FileExplorerItem explorerItem = item.Content as FileExplorerItem;
CDataObject dataObject = new CDataObject();
if (dataObject != null)
{
List<string> filePaths = GetSelectedListViewItemsPaths();
String fileList = "";
foreach (string filePath in filePaths)
{
fileList += filePath + char.MinValue;
}
fileList += char.MinValue;
// Allocate memory for the DROPFILES structure
int size = Marshal.SizeOf(typeof(DROPFILES)) + (fileList.Length + 2) *2; // Length of the string plus one for the double null terminator
IntPtr hGlobal = Marshal.AllocHGlobal(size);
// Initialize the DROPFILES structure
DROPFILES dropFiles = new DROPFILES();
unsafe
{
dropFiles.pFiles = sizeof(DROPFILES); // Offset to the file list
}
dropFiles.fWide = true; // Indicates that the file list is in Unicode format
byte[] dropFilesBuffer = new byte[size];
IntPtr dropFilesPtr = Marshal.AllocHGlobal(Marshal.SizeOf(dropFiles));
Marshal.StructureToPtr(dropFiles, dropFilesPtr, true);
Marshal.Copy(dropFilesPtr, dropFilesBuffer, 0, Marshal.SizeOf(dropFiles));
Marshal.FreeHGlobal(dropFilesPtr);
// Copy the file list to the global memory
byte[] fileListBuffer = Encoding.Unicode.GetBytes(fileList.ToString());
Marshal.Copy(fileListBuffer, 0, hGlobal + Marshal.SizeOf(typeof(DROPFILES)), fileListBuffer.Length);
// Copy the DROPFILES structure to the global memory
Marshal.Copy(dropFilesBuffer, 0, hGlobal, dropFilesBuffer.Length);
System.Runtime.InteropServices.ComTypes.FORMATETC formatec = new System.Runtime.InteropServices.ComTypes.FORMATETC();
formatec.dwAspect = System.Runtime.InteropServices.ComTypes.DVASPECT.DVASPECT_CONTENT;
formatec.lindex = -1;
formatec.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL;
formatec.cfFormat = (short)DataFormats.GetDataFormat(DataFormats.FileDrop).Id;
System.Runtime.InteropServices.ComTypes.STGMEDIUM stgmedium = new System.Runtime.InteropServices.ComTypes.STGMEDIUM();
stgmedium.tymed = System.Runtime.InteropServices.ComTypes.TYMED.TYMED_HGLOBAL;
stgmedium.unionmember = hGlobal;
IntPtr hwnd = new WindowInteropHelper(Application.Current.MainWindow).Handle;
dataObject.SetData(ref formatec, ref stgmedium, true);
try
{
int hr = DragHelper.SHDoDragDrop(hwnd, dataObject, null, DragDropEffects.Copy, out var result);
if (hr < 0)
{
throw Marshal.GetExceptionForHR(hr);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
Marshal.FreeHGlobal(hGlobal);
}
else
{
// handle the case when dataObject is null
}
}
}
A successfull drop is performed on Windows Exlporer, hResult returns 262400, but nothing happens the file doesnt get copied, it is as no file drop ever happend.
My guess is that there is something wrong with the way i provide the filepaths to the DROPFILES Struct, but i cant figure it out.
I tried differnt ways of providing the filepaths to the struct but nothing helps.
Maybe somebody can lead me on the right path?
I want to write some data to a USB port and receive an answer from it.
I actually used the same
string cmdLine = "#00WD3000C82B*\r";
and sent it to the same machine with the SerialPort object and by using rs235 port.
its do well.. and I got the right answer
using these methods:
omronAX.WriteAction("3000", 200.ToString("0000"));
public void WriteAction(string DM_address, string Data)
{
write_action(DM_address, Data);
}
private void write_action(string DM_address, string Data)
{
GotData = "";
Puredata = "";
EndCode = "";
try
{
int ErCd = Write_2_port("WD", DM_address, Data);
if (ErCd != 0) { return; }
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private int Write_2_port(string cod_cmd, string Addr, string Data2write)
{
DReady = false;
out_data = "";
end_c = "";
char cr = Convert.ToChar(13);
string cmd = "", Dat1 = "", Dat2 = "";
Mess = "";
Dat2 = Data2write;
if (Addr.Trim().Length > 0)
{
try
{
Dat1 = String.Format("{0:0000}", Convert.ToInt16(Addr));
}
catch (FormatException ex)
{
Mess = ex.Message;
return 1;
}
catch (OverflowException ex1)
{
Mess = ex1.Message;
return 3;
}
}
int.TryParse(Dat2, out int hex);
string hexValue = hex.ToString("X");
cmd = "#" + BakN + cod_cmd + Dat1 + hexValue ;
string send2port = cmd + Checksm(cmd) + "*" + cr;
SentCommand = send2port;
try
{
// if (Sport.IsOpen == false) { Sport.Open(); }
locking = true;
Sport.WriteTimeout = 5000;
Sport.WriteLine(send2port);
int i = 0;
while (locking)
{
if (i++ == 500)
{
throw new TimeoutException("יתכן שיש בעיות תקשורת עם המערכת.");
}
Thread.Sleep(10);
}
// T:System.ArgumentNullException:
// The str parameter is null.
//
// T:System.InvalidOperationException:
// The specified port is not open.
//
// T:System.TimeoutException:
// The System.IO.Ports.SerialPort.WriteLine(System.String) method could not write
// to the stream.
}
catch (TimeoutException ex)
{
Mess = ex.Message;
throw ex;
}
catch (Exception ex)
{
Mess = ex.Message;
return 2;
}
return 0;
}
for the next code, I try using USB port and write to it the same line...
But I got nothing when I read the answer back and I got (bytesRead = 0)
in my bytesWritten, I got 15...
using System;
using System.Text;
using System.Text.RegularExpressions;
using LibUsbDotNet;
using LibUsbDotNet.Main;
namespace Examples
{
internal class ReadWrite
{
public static UsbDevice MyUsbDevice;
#region SET YOUR USB Vendor and Product ID!
public static UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x0590,0x005B);
#endregion
public static void Main(string[] args)
{
ErrorCode ec = ErrorCode.None;
try
{
// Find and open the USB device.
MyUsbDevice = UsbDevice.OpenUsbDevice(MyUsbFinder);
// If the device is open and ready
if (MyUsbDevice == null) throw new Exception("Device Not Found.");
// If this is a "whole" usb device (libusb-win32, linux libusb)
// it will have an IUsbDevice interface. If not (WinUSB) the
// variable will be null indicating this is an interface of a
// device.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// This is a "whole" USB device. Before it can be used,
// the desired configuration and interface must be selected.
// Select config #1
wholeUsbDevice.SetConfiguration(1);
// Claim interface #0.
wholeUsbDevice.ClaimInterface(0);
}
// open read endpoint 1.
UsbEndpointReader reader = MyUsbDevice.OpenEndpointReader(ReadEndpointID.Ep01);
// open write endpoint 1.
UsbEndpointWriter writer = MyUsbDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
// Remove the exepath/startup filename text from the begining of the CommandLine.
//string cmdLine = Regex.Replace(Environment.CommandLine, "^\".+?\"^.*? |^.*? ", "", RegexOptions.Singleline);
string cmdLine = "#00WD3000A11*\r";
if (!String.IsNullOrEmpty(cmdLine))
{
int bytesWritten;
ec = writer.Write(Encoding.Default.GetBytes(cmdLine), 20000000, out bytesWritten);
if (ec != ErrorCode.None) throw new Exception(UsbDevice.LastErrorString);
byte[] readBuffer = new byte[1024];
while (ec == ErrorCode.None)
{
int bytesRead;
// If the device hasn't sent data in the last 100 milliseconds,
// a timeout error (ec = IoTimedOut) will occur.
ec = reader.Read(readBuffer, 100, out bytesRead);
if (bytesRead == 0) throw new Exception("No more bytes!");
// Write that output to the console.
Console.Write(Encoding.Default.GetString(readBuffer, 0, bytesRead));
}
Console.WriteLine("\r\nDone!\r\n");
}
else
throw new Exception("Nothing to do.");
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine((ec != ErrorCode.None ? ec + ":" : String.Empty) + ex.Message);
}
finally
{
if (MyUsbDevice != null)
{
if (MyUsbDevice.IsOpen)
{
// If this is a "whole" usb device (libusb-win32, linux libusb-1.0)
// it exposes an IUsbDevice interface. If not (WinUSB) the
// 'wholeUsbDevice' variable will be null indicating this is
// an interface of a device; it does not require or support
// configuration and interface selection.
IUsbDevice wholeUsbDevice = MyUsbDevice as IUsbDevice;
if (!ReferenceEquals(wholeUsbDevice, null))
{
// Release interface #0.
wholeUsbDevice.ReleaseInterface(0);
}
MyUsbDevice.Close();
}
MyUsbDevice = null;
// Free usb resources
UsbDevice.Exit();
}
// Wait for user input.
Console.ReadKey();
}
}
}
}
I have no idea and I am doing wrong, thanks.
I recommend using Usb.Net (https://github.com/MelbourneDeveloper/Device.Net) instead of LibUsb. The problem with LibUsb is that is just wraps WinUSB calls. So, you are deploying an extra C dll (LibUsb) that just points to an existing Windows C DLL. LibUsb is good if you want to keep the code cross platform with Linux, but otherwise, there's not much point.
Here is sample WinUsb code (https://github.com/MelbourneDeveloper/Device.Net/blob/master/src/Usb.Net/Windows/WindowsUsbDevice.cs)
public override Task InitializeAsync()
{
Dispose();
int errorCode;
if (string.IsNullOrEmpty(DeviceId))
{
throw new WindowsException($"{nameof(DeviceDefinition)} must be specified before {nameof(InitializeAsync)} can be called.");
}
_DeviceHandle = APICalls.CreateFile(DeviceId, (APICalls.GenericWrite | APICalls.GenericRead), APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting, APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);
if (_DeviceHandle.IsInvalid)
{
//TODO: is error code useful here?
errorCode = Marshal.GetLastWin32Error();
if (errorCode > 0) throw new Exception($"Device handle no good. Error code: {errorCode}");
}
var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var defaultInterfaceHandle);
HandleError(isSuccess, "Couldn't initialize device");
var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));
isSuccess = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, 0, out _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
HandleError(isSuccess, "Couldn't get device descriptor");
byte i = 0;
//Get the first (default) interface
var defaultInterface = GetInterface(defaultInterfaceHandle);
_UsbInterfaces.Add(defaultInterface);
while (true)
{
isSuccess = WinUsbApiCalls.WinUsb_GetAssociatedInterface(defaultInterfaceHandle, i, out var interfacePointer);
if (!isSuccess)
{
errorCode = Marshal.GetLastWin32Error();
if (errorCode == APICalls.ERROR_NO_MORE_ITEMS) break;
throw new Exception($"Could not enumerate interfaces for device {DeviceId}. Error code: { errorCode}");
}
var associatedInterface = GetInterface(interfacePointer);
_UsbInterfaces.Add(associatedInterface);
i++;
}
IsInitialized = true;
RaiseConnected();
return Task.CompletedTask;
}
However, I did submit this sample to LibUsbDotNet and it's now the accepted Read/Write sample there (https://github.com/LibUsbDotNet/LibUsbDotNet/blob/master/src/Examples/Read.Write/ReadWrite.cs):
public static void Main(string[] args)
{
using (var context = new UsbContext())
{
context.SetDebugLevel(LogLevel.Info);
//Get a list of all connected devices
var usbDeviceCollection = context.List();
//Narrow down the device by vendor and pid
var selectedDevice = usbDeviceCollection.FirstOrDefault(d => d.ProductId == ProductId && d.VendorId == VendorId);
//Open the device
selectedDevice.Open();
//Get the first config number of the interface
selectedDevice.ClaimInterface(selectedDevice.Configs[0].Interfaces[0].Number);
//Open up the endpoints
var writeEndpoint = selectedDevice.OpenEndpointWriter(WriteEndpointID.Ep01);
var readEnpoint = selectedDevice.OpenEndpointReader(ReadEndpointID.Ep01);
//Create a buffer with some data in it
var buffer = new byte[64];
buffer[0] = 0x3f;
buffer[1] = 0x23;
buffer[2] = 0x23;
//Write three bytes
writeEndpoint.Write(buffer, 3000, out var bytesWritten);
var readBuffer = new byte[64];
//Read some data
readEnpoint.Read(readBuffer, 3000, out var readBytes);
}
}
I had an issue getting my device to connect with another library because I was using upper case for alphabetic characters in the VID/PID. Have you tried using lower case ("0x005b" instead of "0x005B")?
In my project i want list out all files under a specific file path.Do to some user permission issue am using master file table to access all files.
Using this thread I can able to read all files under a specific file location
This one will list the file name and parent FRN,is there any way to list the file attributes also????
I want to show these details also.
Created Date
Modified Data
File Size
USN_RECORD contains these details.
You'd probably be better off using something more high-level to enumerate the contents of a path (as suggested by #HarryJohnston), but if you're determined to go down the route you've chosen, then...
Using the FileReferenceNumber you got from your USN call, you can call OpenFileByID (specifying a 0 for the dwDesiredAccess parameter - no read, no write), and you can then subsequently call GetFileInformationByHandle to get the details you need.
You don't need read or write permissions on the file to call GetFileInformationByHandle. The file attributes you're getting from the USN call and/or the GetFileInformationByHandle call can be cast to a .Net System.IO.FileAttributes.
public IEnumerable<FileDetails> EnumerateFiles(string szDriveLetter)
{
List<FileDetails> fdList = new List<FileDetails>();
try
{
var usnRecord = default(USN_RECORD);
var mft = default(MFT_ENUM_DATA);
var dwRetBytes = 0;
int cb;
var dicFrnLookup = new Dictionary<long, FSNode>();
bool bIsFile;
// This shouldn't be called more than once.
if (m_Buffer.ToInt32() != 0)
{
throw new Exception("invalid buffer");
}
// Assign buffer size
m_BufferSize = 65536;
//64KB
// Allocate a buffer to use for reading records.
m_Buffer = Marshal.AllocHGlobal(m_BufferSize);
// correct path
szDriveLetter = szDriveLetter.TrimEnd('\\');
// Open the volume handle
m_hCJ = OpenVolume(szDriveLetter);
uint iny = NativeMethods.GetLastError();
// Check if the volume handle is valid.
if (m_hCJ == INVALID_HANDLE_VALUE)
{
throw new Exception("Couldn't open handle to the volume.");
}
mft.StartFileReferenceNumber = 0;
mft.LowUsn = 0;
mft.HighUsn = long.MaxValue;
do
{
if (DeviceIoControl(m_hCJ, FSCTL_ENUM_USN_DATA, ref mft, Marshal.SizeOf(mft), m_Buffer, m_BufferSize, ref dwRetBytes, IntPtr.Zero))
{
cb = dwRetBytes;
// Pointer to the first record
IntPtr pUsnRecord = new IntPtr(m_Buffer.ToInt32() + 8);
while ((dwRetBytes > 8))
{
// Copy pointer to USN_RECORD structure.
usnRecord = (USN_RECORD)Marshal.PtrToStructure(pUsnRecord, usnRecord.GetType());
// The filename within the USN_RECORD.
string fileName = Marshal.PtrToStringUni(new IntPtr(pUsnRecord.ToInt32() + usnRecord.FileNameOffset), usnRecord.FileNameLength / 2);
bIsFile = !usnRecord.FileAttribute.HasFlag(FileAttributes.Directory);
dicFrnLookup.Add(usnRecord.FileReferenceNumber, new FSNode(usnRecord.ParentFileReferenceNumber, fileName, bIsFile));
// Pointer to the next record in the buffer.
pUsnRecord = new IntPtr(pUsnRecord.ToInt32() + usnRecord.RecordLength);
dwRetBytes -= usnRecord.RecordLength;
}
// The first 8 bytes is always the start of the next USN.
mft.StartFileReferenceNumber = Marshal.ReadInt64(m_Buffer, 0);
}
else
{
break; // TODO: might not be correct. Was : Exit Do
}
} while (!(cb <= 8));
// Resolve all paths for Files
foreach (FSNode oFSNode in dicFrnLookup.Values.Where(o => o.IsFile))
{
FileDetails fd = new FileDetails();
string sFullPath = oFSNode.FileName;
FSNode oParentFSNode = oFSNode;
while (dicFrnLookup.TryGetValue(oParentFSNode.ParentFRN, out oParentFSNode))
{
sFullPath = string.Concat(oParentFSNode.FileName, "\\", sFullPath);
}
sFullPath = string.Concat(szDriveLetter, "\\", sFullPath);
//File Attribute details
WIN32_FILE_ATTRIBUTE_DATA data;
if (NativeMethods.GetFileAttributesEx(#sFullPath, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out data))
{
fd.FileSize = Convert.ToDouble(data.fileSizeLow);
}
long highBits = data.creationTime.dwHighDateTime;
highBits = highBits << 32;
DateTime createdDate = DateTime.FromFileTimeUtc(highBits + (uint)data.creationTime.dwLowDateTime);
fd.CreatedDate = createdDate.ToString(CultureInfo.CurrentCulture);
fd.CreatedYear = createdDate.Year;
fd.FileType = data.filetype;
long highBitsModified = data.lastWriteTime.dwHighDateTime;
highBitsModified = highBitsModified << 32;
DateTime modifiedDate = DateTime.FromFileTimeUtc(highBitsModified + (uint)data.creationTime.dwLowDateTime);
fd.ModifiedYear = modifiedDate.Year;
fd.ModifiedDate = modifiedDate.ToString(CultureInfo.CurrentCulture);
fd.FilePath = sFullPath;
fd.MachineName = SystemInformation.ComputerName;
List<string> names = sFullPath.Split('.').ToList();
fd.FileType = "." + names.LastOrDefault();
List<string> folders = sFullPath.Split('\\').ToList();
//fd.FileName = folders.LastOrDefault();
fd.FileName = oFSNode.FileName;
fdList.Add(fd);
yield return fd;
}
}
finally
{
//// cleanup
Cleanup();
}
}
public class NativeMethods
{
[DllImport("KERNEL32.dll", CharSet = CharSet.None)]
public static extern bool GetFileAttributesEx(string path, GET_FILEEX_INFO_LEVELS level, out WIN32_FILE_ATTRIBUTE_DATA data);
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
}
I am developing a c# .net 3.5 application (compiled to anycpu)
I need to sign an executable. I tried to use the code in here with some modifications.
I didn't search for the certificate in the store, instead I loaded it form a pfx file:
var cert = new X509Certificate2("myCert.pfx", "pass");
And change method sign like this:
public static void Sign(string appPath, X509Certificate2 cert)
{
var pSignerCert = IntPtr.Zero;
var pSubjectInfo = IntPtr.Zero;
var pSignatureInfo = IntPtr.Zero;
var pProviderInfo = IntPtr.Zero;
pSignerCert = CreateSignerCert(cert);
pSubjectInfo = CreateSignerSubjectInfo(appPath);
pSignatureInfo = CreateSignerSignatureInfo();
pProviderInfo = GetProviderInfo(cert);
var hResult = NativeMethods.SignerSign(
pSubjectInfo,
pSignerCert,
pSignatureInfo,
pProviderInfo,
null,
IntPtr.Zero,
IntPtr.Zero
);
Console.WriteLine(hResult);
}
and then I am getting the provider info like this:
private static IntPtr GetProviderInfo(X509Certificate2 cert)
{
if (cert == null || !cert.HasPrivateKey)
{
return IntPtr.Zero;
}
var key = cert.PublicKey.Key as ICspAsymmetricAlgorithm;
if (key == null)
{
return IntPtr.Zero;
}
var providerInfo = new SignerProviderInfo
{
cbSize = (uint)Marshal.SizeOf(typeof(SignerProviderInfo)),
pwszProviderName = "Microsoft Enhanced Cryptographic Provider v1.0",
dwProviderType = 0x1,
// PROV_RSA_FULL
dwKeySpec = 0x0,
dwPvkChoice = 0x2, //PVK_TYPE_KEYCONTAINER
providerUnion = new SignerProviderInfo.ProviderInfoUnion
{
pwszKeyContainer = key.CspKeyContainerInfo.KeyContainerName
},
};
var pProviderInfo = Marshal.AllocHGlobal(Marshal.SizeOf(providerInfo));
Marshal.StructureToPtr(providerInfo, pProviderInfo, false);
return pProviderInfo;
}
the issue is that on some machines it works perfectly ok, but on some other machine I get the following error: Error code 0x80092006 - No provider was specified for the store or object.
I tried to use SignTool.exe with the same pfx file and it works ok.
I tried to investigate what might cause this behavior, but I couldn't find any hint for wht this error is happening.
Does anyone knows why it might happen?
provider info should be filled like this instead:
// get private key information
ICspAsymmetricAlgorithm key = (ICspAsymmetricAlgorithm)certificate.PrivateKey;
const int PVK_TYPE_KEYCONTAINER = 2;
var providerInfo = new SignerProviderInfo
{
cbSize = (uint)Marshal.SizeOf(typeof(SignerProviderInfo)),
pwszProviderName = key.CspKeyContainerInfo.ProviderName,
dwProviderType = (uint)key.CspKeyContainerInfo.ProviderType,
dwPvkChoice = PVK_TYPE_KEYCONTAINER,
providerUnion = new SignerProviderInfo.ProviderInfoUnion
{
pwszKeyContainer = key.CspKeyContainerInfo.KeyContainerName
},
};
I want to enable drag and drop from our windows forms based application to Windows Explorer. The big problem: The files are stored in a database, so I need to use delayed data rendering. There is an article on codeproject.com, but the author is using a H_GLOBAL object which leads to memory problems with files bigger than aprox. 20 MB. I haven't found a working solution for using an IStream Object instead. I think this must be possible to implement, because this isn't an unusual case. (A FTP program needs such a feature too, for example)
Edit: Is it possible to get an event when the user drops the file? So I could for example copy it to temp and the explorer gets it from there? Maybe there is an alternative approach for my problem...
AFAIK, there is not working article about this for .net. So you should write it by yourself, this is somewhat complicate, because .net DataObject class is limited. I have working example of the opposite task (accepting delayed rendering files from explorer), but it is easier, because I do not needed own IDataObject implementation.
So your task will be:
Find working IDataObject implementation in .net. I recommend you look here (Shell Style Drag and Drop in .NET (WPF and WinForms))
You also need an IStream wrapper for managed stream (it is relatively easy to implement)
Implement delayed rendering using information from MSDN (Shell Clipboard Formats)
This is the starting point, and in general enough information to implement such feature. With bit of patience and several unsuccessful attempts you will do it :)
Update: The following code lacks many necessary methods and functions, but the main logic is here.
// ...
private static IEnumerable<IVirtualItem> GetDataObjectContent(System.Windows.Forms.IDataObject dataObject)
{
if (dataObject == null)
return null;
List<IVirtualItem> Result = new List<IVirtualItem>();
bool WideDescriptor = dataObject.GetDataPresent(ShlObj.CFSTR_FILEDESCRIPTORW);
bool AnsiDescriptor = dataObject.GetDataPresent(ShlObj.CFSTR_FILEDESCRIPTORA);
if (WideDescriptor || AnsiDescriptor)
{
IDataObject NativeDataObject = dataObject as IDataObject;
if (NativeDataObject != null)
{
object Data = null;
if (WideDescriptor)
Data = dataObject.GetData(ShlObj.CFSTR_FILEDESCRIPTORW);
else
if (AnsiDescriptor)
Data = dataObject.GetData(ShlObj.CFSTR_FILEDESCRIPTORA);
Stream DataStream = Data as Stream;
if (DataStream != null)
{
Dictionary<string, VirtualClipboardFolder> FolderMap =
new Dictionary<string, VirtualClipboardFolder>(StringComparer.OrdinalIgnoreCase);
BinaryReader Reader = new BinaryReader(DataStream);
int Count = Reader.ReadInt32();
for (int I = 0; I < Count; I++)
{
VirtualClipboardItem ClipboardItem;
if (WideDescriptor)
{
FILEDESCRIPTORW Descriptor = ByteArrayHelper.ReadStructureFromStream<FILEDESCRIPTORW>(DataStream);
if (((Descriptor.dwFlags & FD.FD_ATTRIBUTES) > 0) && ((Descriptor.dwFileAttributes & FileAttributes.Directory) > 0))
ClipboardItem = new VirtualClipboardFolder(Descriptor);
else
ClipboardItem = new VirtualClipboardFile(Descriptor, NativeDataObject, I);
}
else
{
FILEDESCRIPTORA Descriptor = ByteArrayHelper.ReadStructureFromStream<FILEDESCRIPTORA>(DataStream);
if (((Descriptor.dwFlags & FD.FD_ATTRIBUTES) > 0) && ((Descriptor.dwFileAttributes & FileAttributes.Directory) > 0))
ClipboardItem = new VirtualClipboardFolder(Descriptor);
else
ClipboardItem = new VirtualClipboardFile(Descriptor, NativeDataObject, I);
}
string ParentFolder = Path.GetDirectoryName(ClipboardItem.FullName);
if (string.IsNullOrEmpty(ParentFolder))
Result.Add(ClipboardItem);
else
{
VirtualClipboardFolder Parent = FolderMap[ParentFolder];
ClipboardItem.Parent = Parent;
Parent.Content.Add(ClipboardItem);
}
VirtualClipboardFolder ClipboardFolder = ClipboardItem as VirtualClipboardFolder;
if (ClipboardFolder != null)
FolderMap.Add(PathHelper.ExcludeTrailingDirectorySeparator(ClipboardItem.FullName), ClipboardFolder);
}
}
}
}
return Result.Count > 0 ? Result : null;
}
// ...
public VirtualClipboardFile : VirtualClipboardItem, IVirtualFile
{
// ...
public Stream Open(FileMode mode, FileAccess access, FileShare share, FileOptions options, long startOffset)
{
if ((mode != FileMode.Open) || (access != FileAccess.Read))
throw new ArgumentException("Only open file mode and read file access supported.");
System.Windows.Forms.DataFormats.Format Format = System.Windows.Forms.DataFormats.GetFormat(ShlObj.CFSTR_FILECONTENTS);
if (Format == null)
return null;
FORMATETC FormatEtc = new FORMATETC();
FormatEtc.cfFormat = (short)Format.Id;
FormatEtc.dwAspect = DVASPECT.DVASPECT_CONTENT;
FormatEtc.lindex = FIndex;
FormatEtc.tymed = TYMED.TYMED_ISTREAM | TYMED.TYMED_HGLOBAL;
STGMEDIUM Medium;
FDataObject.GetData(ref FormatEtc, out Medium);
try
{
switch (Medium.tymed)
{
case TYMED.TYMED_ISTREAM:
IStream MediumStream = (IStream)Marshal.GetTypedObjectForIUnknown(Medium.unionmember, typeof(IStream));
ComStreamWrapper StreamWrapper = new ComStreamWrapper(MediumStream, FileAccess.Read, ComRelease.None);
// Seek from beginning
if (startOffset > 0)
if (StreamWrapper.CanSeek)
StreamWrapper.Seek(startOffset, SeekOrigin.Begin);
else
{
byte[] Null = new byte[256];
int Readed = 1;
while ((startOffset > 0) && (Readed > 0))
{
Readed = StreamWrapper.Read(Null, 0, (int)Math.Min(Null.Length, startOffset));
startOffset -= Readed;
}
}
StreamWrapper.Closed += delegate(object sender, EventArgs e)
{
ActiveX.ReleaseStgMedium(ref Medium);
Marshal.FinalReleaseComObject(MediumStream);
};
return StreamWrapper;
case TYMED.TYMED_HGLOBAL:
byte[] FileContent;
IntPtr MediumLock = Windows.GlobalLock(Medium.unionmember);
try
{
long Size = FSize.HasValue ? FSize.Value : Windows.GlobalSize(MediumLock).ToInt64();
FileContent = new byte[Size];
Marshal.Copy(MediumLock, FileContent, 0, (int)Size);
}
finally
{
Windows.GlobalUnlock(Medium.unionmember);
}
ActiveX.ReleaseStgMedium(ref Medium);
Stream ContentStream = new MemoryStream(FileContent, false);
ContentStream.Seek(startOffset, SeekOrigin.Begin);
return ContentStream;
default:
throw new ApplicationException(string.Format("Unsupported STGMEDIUM.tymed ({0})", Medium.tymed));
}
}
catch
{
ActiveX.ReleaseStgMedium(ref Medium);
throw;
}
}
// ...
Googlers may find this useful: download a file using windows IStream