flash drive imaging - c#

I would like to write an application that will create an 'image' of a flash drive. This includes the total topography of the drive, not just the files. So if the drive is 4GB you get a 4GB file. Is this possible, and if so, could someone point me in the direction of information on how this may be accomplished?

It is possible. I did it for an internal app, so I can't just paste the source for it, but I can give you some hints. You will have to P/Invoke some things.
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "CreateFileW", SetLastError = true)]
public static extern IntPtr CreateFile(string name, int access, int share, byte[] attributes, int create, int flags, IntPtr template);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int DeviceIoControl(IntPtr handle, DiskIoctl ioctl, byte[] inBuffer, int inBufferSize, byte[] outBuffer, int outBufferSize, ref int bytesReturned, IntPtr overlapped);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, EntryPoint = "GetLogicalDriveStringsW", SetLastError = true)]
public static extern int GetLogicalDriveStrings(int bufferLength, byte[] buffer);
public enum DiskIoctl
{
ScsiPassThrough = 315396,
Lock = 589848,
Unlock = 589852,
Dismount = 589856,
UpdateProperties = 459072,
GetDiskLayout = 475148,
SetDiskLayout = 507920
}
public enum ScsiOp
{
ReadCapacity = 0x25,
Read = 0x28,
Write = 0x2A
}

Have you tried simply opening the drive as a file and copying it?

Related

How to read print job content using ReadPrinter method

I'd like to get content of a document sent to printing.
Google said an only way to do that is to use WinAPI method ReadPrinter().
I've implemented a sketch but can't get it work.
A trouble is the ReadPrinter() method always returns nothing.
Please give me a hint what is wrong.
Simplified code below:
string printerName = "Microsoft XPS Document Writer";
const uint firstJob = 0u;
const uint noJobs = 10u;
const uint level = 1u;
uint bytesNeeded;
uint returned;
uint bytesCopied;
uint structsCopied;
// Open printer
IntPtr printerHandle = OpenPrinterW(printerName.Normalize(), out printerHandle, IntPtr.Zero);
// Get byte size required for a data
EnumJobsW(printerHandle, firstJob, noJobs, level, IntPtr.Zero, 0, out bytesNeeded, out returned);
// Now we know how much memory we need to read the data (bytesNeeded value)
IntPtr pJob = Marshal.AllocHGlobal((int)bytesNeeded);
// Read the data
EnumJobsW(printerHandle, firstJob, noJobs, level, pJob, bytesNeeded, out bytesCopied, out structsCopied);
// Convert pJob to jobInfos
JOB_INFO_1W[] jobInfos = null;
// ... actual convert code missed ...
// Iterate through the jobs and try to get their content
foreach (JOB_INFO_1W jobInfo in jobInfos)
{
// Open print job
string printJobName = string.Format("{0}, Job {1}", printerName, jobInfo.JobId);
IntPtr printJobHandle;
OpenPrinterW(printJobName.Normalize(), out printJobHandle, IntPtr.Zero);
// Read print job
const int printJobBufLen = 1024;
StringBuilder printJobSb = new StringBuilder(printJobBufLen);
int printJobBytesRead = 0;
while (printJobBytesRead == 0)
{
ReadPrinter(printJobHandle, printJobSb, printJobBufLen, out printJobBytesRead);
// !!! printJobBytesRead is 0 and printJobSb is empty
}
// Close print job
ClosePrinter(printJobHandle);
}
// Close printer
ClosePrinter(printerHandle);
P/Invoke signatures:
[DllImport("winspool.drv", EntryPoint = "OpenPrinterW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int OpenPrinterW(
[In] string pPrinterName,
[Out] out IntPtr phPrinter,
[In] IntPtr pDefault);
[DllImport("spoolss.dll", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ClosePrinter(
[In] IntPtr hPrinter);
[DllImport("winspool.drv", EntryPoint = "EnumJobsW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int EnumJobsW(
[In] IntPtr hPrinter,
[In] uint FirstJob,
[In] uint NoJobs,
[In] uint Level,
[Out] IntPtr pJob,
[In] uint cbBuf,
[Out] out uint pcbNeeded,
[Out] out uint pcReturned);
[DllImport("spoolss.dll", EntryPoint = "ReadPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern int ReadPrinter(
[In] IntPtr hPrinter,
[Out] StringBuilder data,
[In] Int32 cbBuf,
[Out] out Int32 pNoBytesRead);
Is this code inside a driver's Print Processor component? (Link updated to web archive.) If not, I don't think it will work.
So you either use a print driver component, or read from the spool file on disk. See here.

Automated Printing with Crystal Reports and PDFs

I am trying to automate one of our daily print jobs.
On the old VBA program...
We are creating the crystal report, grabbing an 8 1/2 x 11 pdf, then grabbing an 11 x 17 pdf
The program then prints these in consecutive order. They are all sent to the same printer, but the 11 x 17 pdf uses another driver specifically for the paper size. Both pdfs are shelled in adobe and printed.
We are now trying to do the same thing in C#, except without shelling. There are still two drivers set up for the printer, and I have been trying to send the raw data directly to them, but I still have one issue...
The 11 x 17 pdfs are not "true" 11 x 17's (sometimes 12.8 x 18.4, etc.). This causes the printer to stop printing (even appear offline) until you select a tray from the physical printer and click start.
I have played with the driver enough to believe that the driver is not the issue, but the program is to blame. I am trying to use winspool to complete this process, but don't know if this is the right approach.`
namespace WorkOrderMass.Helper
{
public class RawPrinterHelper
{[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
PrinterSettings ps = new PrinterSettings();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "PDF Document";
di.pDataType = "RAW";
PrintDocument pd = new PrintDocument();
pd.DefaultPageSettings.PaperSize = new PaperSize("PaperA3", 840, 1180);
pd.Print();
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
System.Threading.Thread.Sleep(5000);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
}
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
bool bSuccess = true;
using (FileStream fs = new FileStream(szFileName, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
Byte[] bytes = new Byte[fs.Length];
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
}
}
return bSuccess;
}
}
}`
Answer: Program is now using SumantraPDF to silently print the PDF's.

Extracting an icon group from a .dll file in C#

I'm trying to extract an icon from imageres.dll. Specifically the "My Computer" or "This PC" icon. The problem is that at between Win7 and Win10, the icon number changes. However, the icon group does not (109). Is there a way to get that icon group, and then let the computer figure out which icon to use of that group, in the same way it figures out which icon to use for my app?
This is the code I'm using to get the specific icon via the index:
public class GetIcon {
public static Icon Extract(string file, int number) {
IntPtr large;
IntPtr small;
ExtractIconEx(file, number, out large, out small, 1);
try {
return Icon.FromHandle(small);
}
catch {
return null;
}
}
[DllImport("Shell32.dll", EntryPoint = "ExtractIconExW", CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern int ExtractIconEx(string sFile, int iIndex, out IntPtr piLargeVersion, out IntPtr piSmallVersion, int amountIcons);
}
Thanks.
There are a couple of ways to do this. The most reliable, and potentially most time consuming (provided you can't find an existing library), is to parse the PE File (i.e. .exe, .dll) and extract the relevant Icon group data yourself. Here's a good resource for the format: https://msdn.microsoft.com/en-us/library/ms809762.aspx
The second way, can be done easily enough with Windows functions, however there is one caveat. It will only work on PE files that are of the same bit-type as your application. So, for example, if your application is 64-bit, it will only work on 64-bit PE files.
Here's a function I just wrote - based off this: https://msdn.microsoft.com/en-us/library/windows/desktop/ms648051(v=vs.85).aspx#_win32_Sharing_Icon_Resources, that takes a file name, group number, and desired icon size, and returns a System.Drawing.Icon
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)]string lpFileName);
[DllImport("kernel32.dll")]
static extern IntPtr FindResource(IntPtr hModule, int lpName, int lpType);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
[DllImport("kernel32.dll")]
static extern IntPtr LockResource(IntPtr hResData);
[DllImport("user32.dll")]
static extern int LookupIconIdFromDirectoryEx(byte[] presbits, bool fIcon, int cxDesired, int cyDesired, uint Flags);
[DllImport("user32.dll")]
static extern IntPtr CreateIconFromResourceEx(byte[] pbIconBits, uint cbIconBits, bool fIcon, uint dwVersion, int cxDesired, int cyDesired, uint uFlags);
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
const int RT_GROUP_ICON = 14;
const int RT_ICON = 0x00000003;
private System.Drawing.Icon GetIconFromGroup(string file, int groupId, int size)
{
IntPtr hExe = LoadLibrary(file);
if(hExe != IntPtr.Zero)
{
IntPtr hResource = FindResource(hExe, groupId, RT_GROUP_ICON);
IntPtr hMem = LoadResource(hExe, hResource);
IntPtr lpResourcePtr = LockResource(hMem);
uint sz = SizeofResource(hExe, hResource);
byte[] lpResource = new byte[sz];
Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz);
int nID = LookupIconIdFromDirectoryEx(lpResource, true, size, size, 0x0000);
hResource = FindResource(hExe, nID, RT_ICON);
hMem = LoadResource(hExe, hResource);
lpResourcePtr = LockResource(hMem);
sz = SizeofResource(hExe, hResource);
lpResource = new byte[sz];
Marshal.Copy(lpResourcePtr, lpResource, 0, (int)sz);
IntPtr hIcon = CreateIconFromResourceEx(lpResource, sz, true, 0x00030000, size, size, 0);
System.Drawing.Icon testIco = System.Drawing.Icon.FromHandle(hIcon);
return testIco;
}
return null;
}
The process basically works like this:
use LoadLibrary to load up the .exe or .dll file
Get the handle & data of the RT_GROUP_ICON resource
Pass the data, along with the desired size to LookupIconIdFromDirectoryEx, to get the icon index
From there, you can either use ExtractIconEx, or just repeat step 2 with the icon index, and RT_ICON instead, followed by using CreateIconFromResourceEx to get your icon handle.

Lighting USB OpenDMX FTD2XX DMXking

Couple of quick questions. I have a DMX king USB lighting controller that I'm trying to control.
It's based on the Open DMX protocol (from Entec) who make available a c# class.
I've got the device plugged into an RGB can, and if I test the USB device with their driver, it connects to COM4 and when I switch their software into transmit mode, I can then set individual DMX channels.
Using their OpenDMX class, with a few modifications (the core is the same, i've just added some extra error checking, I can locate the device, query it's information etc.
When I open the device I get a handle.
I can write to that device with FT_Write but no matter what I do, no lights actually come on.
Here's a few relevant code snippets:
public static byte[] buffer;
[DllImport("FTD2XX.dll")]
public static extern FT_STATUS FT_Open(UInt32 uiPort, ref uint ftHandle);
[DllImport("FTD2XX.dll")]
public static extern FT_STATUS FT_Write(uint ftHandle, IntPtr lpBuffer, UInt32 dwBytesToRead, ref UInt32 lpdwBytesWritten);
public static void writeData()
{
while (!done)
{
try
{
initOpenDMX();
status = FT_SetBreakOn(handle);
status = FT_SetBreakOff(handle);
bytesWritten = write(handle, buffer, buffer.Length);
if (bytesWritten == 0)
{
break;
}
System.Threading.Thread.Sleep(25);
}
catch (Exception)
{
break;
}
}
Connected = false;
done = false;
}
All the status come back as FT_Ok, and bytesWritten comes back as 512 (the number of channels on this USB controller)
I keep thinking I've missed something like setting the device into a transmit mode or similar (it only has one DMX socket)
public static void initOpenDMX()
{
status = FT_ResetDevice(handle);
status = FT_SetDivisor(handle, (char)12); // set baud rate
status = FT_SetDataCharacteristics(handle, BITS_8, STOP_BITS_2, PARITY_NONE);
status = FT_SetFlowControl(handle, (char)FLOW_NONE, 0, 0);
status = FT_ClrRts(handle);
status = FT_SetLatencyTimer(handle, (byte)40);
status = FT_Purge(handle, PURGE_TX);
status = FT_Purge(handle, PURGE_RX);
}
I've also tried the Entec OpenDMX class without any modifications from me and it doesn't seem to do anything either.
Just want to stress that their control software is working fine, so the light and controller are compatible. I think something is missing in the way I'm using FTD2xx.
There's no errors coming through (everything is FT_OK) so this suggests the DLL is working - especially since I can query the device using the FT_ListDevices and FT_GetDeviceInfo methods.
Any ideas?
Gareth
To resolve this, I emailed the manufacturer.
It turned out that the device wasn't OpenDMX, in fact it was a DMXProUSB
The protocol was pretty similar, and it was based on the FTDI chip which is why the code partly worked, but it has a microcontroller in it.
I converted the C++ example controller file to C# and got it all working.
If this ever comes up again, I am happy to share the resulting c# code for the DMXProUSB however with no support.
I have emailed the code to the manfacturer (dmxking) and have placed a copy on github: https://github.com/agrath/Sniper.Lighting.Dmx
Thanks for your help
I ran Hippy's VB version through a mechanical VB to C# translator and found one key
difference. FT_WRITE uses a string to pass data to the unmanaged code. The C# class uses
an IPtr pointing to a byte array.
This version works for me:
using System;
using System.Runtime.InteropServices;
using System.Threading;
// based on Hippy's VB Example
// http://members.westnet.com.au/rowanmac/opendmx.html#tx
// Working link: https://web.archive.org/web/20150217155014/http://members.westnet.com.au:80/rowanmac/opendmx.html
namespace Test
{
class Program
{
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Open(short intDeviceNumber, ref int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Close(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetDivisor(int lngHandle, int div);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Read(int lngHandle, string lpszBuffer, int lngBufferSize, ref int lngBytesReturned);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Write(int lngHandle, string lpszBuffer, int lngBufferSize, ref int lngBytesWritten);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Write(int lngHandle, IntPtr lpBuffer, int lngBufferSize, ref int lngBytesWritten);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetBaudRate(int lngHandle, int lngBaudRate);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetDataCharacteristics(int lngHandle, byte byWordLength, byte byStopBits, byte byParity);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetFlowControl(int lngHandle, short intFlowControl, byte byXonChar, byte byXoffChar);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_ResetDevice(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetDtr(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_ClrDtr(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetRts(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_ClrRts(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_GetModemStatus(int lngHandle, ref int lngModemStatus);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_Purge(int lngHandle, int lngMask);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_GetStatus(int lngHandle, ref int lngRxBytes, ref int lngTxBytes, ref int lngEventsDWord);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_GetQueueStatus(int lngHandle, ref int lngRxBytes);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_GetEventStatus(int lngHandle, ref int lngEventsDWord);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetChars(int lngHandle, byte byEventChar, byte byEventCharEnabled, byte byErrorChar, byte byErrorCharEnabled);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetTimeouts(int lngHandle, int lngReadTimeout, int lngWriteTimeout);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetBreakOn(int lngHandle);
[DllImport("FTD2XX.DLL", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int FT_SetBreakOff(int lngHandle);
// FTDI Constants
const short FT_OK = 0;
const short FT_INVALID_HANDLE = 1;
const short FT_DEVICE_NOT_FOUND = 2;
const short FT_DEVICE_NOT_OPENED = 3;
const short FT_IO_ERROR = 4;
const short FT_INSUFFICIENT_RESOURCES = 5;
// Word Lengths
const byte FT_BITS_8 = 8;
// Stop Bits
const byte FT_STOP_BITS_2 = 2;
// Parity
const byte FT_PARITY_NONE = 0;
// Flow Control
const byte FT_FLOW_NONE = 0x0;
// Purge rx and tx buffers
const byte FT_PURGE_RX = 1;
const byte FT_PURGE_TX = 2;
public static int handle=0;
public static byte[] buffer = new byte[4]; // can be up to 512, shorter is faster
private static string lpszBuffer=""+ (char) 0 + (char) 64 + (char) 64+ (char) 0;
static void Main(string[] args)
{
init();
}
public static string init()
{
short n = 0;
// ==== ATTEMPT TO OPEN DEVICE ====
if (FT_Open(n, ref handle) != FT_OK)
{
return "FTTD Not Found";
}
// ==== PREPARE DEVICE FOR DMX TRANSMISSION ====
// reset the device
if (FT_ResetDevice(handle) != FT_OK)
{
return "Failed To Reset Device!";
}
// get an ID from the widget from jumpers
// GetID(ref n);
// set the baud rate
if (FT_SetDivisor(handle, 12) != FT_OK)
{
return "Failed To Set Baud Rate!";
}
// shape the line
if (FT_SetDataCharacteristics(handle, FT_BITS_8, FT_STOP_BITS_2, FT_PARITY_NONE) != FT_OK)
{
return "Failed To Set Data Characteristics!";
}
// no flow control
if (FT_SetFlowControl(handle, FT_FLOW_NONE, 0, 0) != FT_OK)
{
return "Failed to set flow control!";
}
// set bus transiever to transmit enable
if (FT_ClrRts(handle) != FT_OK)
{
return "Failed to set RS485 to send!";
}
// Clear TX & RX buffers
if (FT_Purge(handle, FT_PURGE_TX) != FT_OK)
{
return "Failed to purge TX buffer!";
}
// empty buffers
if (FT_Purge(handle, FT_PURGE_RX) != FT_OK)
{
return "Failed to purge RX buffer!";
}
setDmxValue(0, 0); // should always be zero
setDmxValue(1, 64);
setDmxValue(2, 64);
setDmxValue(3, 0);
Thread thread = new Thread(new ThreadStart(writeDataThread));
thread.Start();
return "Ok";
}
// init
public static void setDmxValue(int channel, byte value)
{
buffer[channel] = value;
lpszBuffer="";
for (int i = 0; i < buffer.Length; ++i)
{
lpszBuffer += (char)buffer[i];
}
}
public static void writeDataThread()
{
bool done = false;
int lngBytesWritten=0;
while (!done)
{
FT_SetBreakOn(handle);
FT_SetBreakOff(handle);
FT_Write(handle, lpszBuffer, buffer.Length, ref lngBytesWritten);
System.Threading.Thread.Sleep(50);
}
}
}
}
I wrote the C# class on the open dmx site.
It was based on Hippy's Open DMX driver written in VB.
// Old broken link:
http://members.westnet.com.au/rowanmac/opendmx.html#tx
// Working link: https://web.archive.org/web/20150217155014/http://members.westnet.com.au:80/rowanmac/opendmx.html
The C# Class in not initializing something on the FDDI chip.
This has been tormenting me for years.
I have my suspicions about FT_SetFlowControl. In the VB app, the second parameter is a short int. But any call to it's equivalent in the C# class will only work if the second parameter is cast to a char.
[DllImport("FTD2XX.dll")]
public static extern FT_STATUS FT_SetFlowControl(uint ftHandle, UInt16 usFlowControl, byte uXon, byte uXoff);
I fix the problem with Marshal.Copy
public static void writeDataThread(int Length)
{
int lngBytesWritten = 0;
IntPtr pnt = Marshal.AllocHGlobal(Length);
Marshal.Copy(buffer, 0, pnt, Length);
FT_SetBreakOn(handle);
FT_SetBreakOff(handle);
string StartCode = null;
FT_Write(handle, StartCode, 1, ref lngBytesWritten);
FT_Write(handle, pnt, Length, ref lngBytesWritten);
}
FTDI chips have GPIO pins in addition to the serial ports. Hopefully the documentation tells you whether these need to be set. The function is FT_SetBitMode. Documentation here.

Change file LastWriteDate in Compact Framework

FileSystemInfo.LastWriteTime property is readonly in CF.
Is there an alternative way to change that date?
P/Invoke SetFileTime.
EDIT
Something along these lines (warning: untested)
[DllImport("coredll.dll")]
private static extern bool SetFileTime(string path,
ref long creationTime,
ref long lastAccessTime,
ref long lastWriteTime);
public void SetFileTimes(string path, DateTime time)
{
var ft = time.ToFileTime();
SetFileTime(path, ref ft, ref ft, ref ft);
}
Here is a fuller implementation, adapted from the answer ctacke provides above and this StackOverflow question. I hope this proves useful to someone:
// Some Windows constants
// File access (using CreateFileW)
public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const uint GENERIC_READ_WRITE = (GENERIC_READ + GENERIC_WRITE);
public const int INVALID_HANDLE_VALUE = -1;
// File creation (using CreateFileW)
public const int CREATE_NEW = 1;
public const int OPEN_EXISTING = 3;
// File attributes (using CreateFileW)
public const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
// P/Invokes
[DllImport("coredll.dll", SetLastError = true)]
public static extern IntPtr CreateFileW(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr pSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplatefile);
[DllImport("coredll.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr hObject);
// Note: Create related P/Invokes to change creation or last access time.
// This one modifies the last write time only.
[DllImport("coredll.dll", EntryPoint = "SetFileTime", SetLastError = true)]
private static extern bool SetFileWriteTime(
IntPtr hFile,
IntPtr lpCreationTimeUnused,
IntPtr lpLastAccessTimeUnused,
ref long lpLastWriteTime);
// Open a handle to the file you want changed
IntPtr hFile = CreateFileW(
path, GENERIC_READ_WRITE, 0,
IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
// Modify the last write time and close the file
long lTimeNow = DateTime.Now.ToFileTime();
SetFileWriteTime(hFile, IntPtr.Zero, IntPtr.Zero, ref lTimeNow);
CloseHandle(hFile);
Note that you can use System.IO.File.GetLastWriteTime (which is exposed in the .NET Compact Framework) to read the last write time if required.

Categories

Resources