|
|
He was so casual about "error 5" that I assumed everyone knew what it meant, except me ...and it was somehow not relevant.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
Yeah, At least one of his problems is ERROR_ACCESS_DENIED but it's entirely possible that there are other errors. I don't see anything else that stands out. I guess it would be nice to know how the SafeFileHandle hdrive is obtained.
|
|
|
|
|
Radnor,
You were on the right track. The program was running as administrator so the "Access denied" was confusing me as well. The SafeFileHandle was created like this ...
using (dd = new FileStream(path + ".dd", FileMode.Open, FileAccess.Write, FileShare.Write))
{
bool finished = NativeMethods.GetSparseRange(ldd.SafeFileHandle, query, ref response, 1024);
}
So when the DeviceIoControl was called the file was empty which for some reason caused the return code 5.
Changing the FileStream creation for an existing file stopped the error.
However now I get an 0x00000057 error, parameter error which brings me back to the original question as how to pass an array of structures to DeviceIoControl.
This is what I've tried, the output buffer is the issue I think....
public static bool GetSparseRange(SafeFileHandle hdrive, in FILE_ALLOCATED_RANGE_BUFFER query, ref FILE_ALLOCATED_RANGE_BUFFER[] response, int count)
{
int nInBufferSize = (int)Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER));
IntPtr lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
Marshal.StructureToPtr(query, lpInBuffer, true);
uint bytesread=0;
int nOutBufferSize = nInBufferSize * count;
IntPtr lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
bool rc = DeviceIoControl(
hdrive,
(uint)EIOControlCode.FsctlQueryAllocatedRanges,
lpInBuffer, (uint)nInBufferSize,
lpOutBuffer, (uint)nOutBufferSize,
ref bytesread,
IntPtr.Zero);
int error = Marshal.GetLastWin32Error();
Marshal.PtrToStructure(lpOutBuffer, response);
Marshal.FreeHGlobal(lpInBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
return rc;
}
Thanks
|
|
|
|
|
Hello,
Your GetSparseRange function is working for me. I simply wrote a quick test application and used the function you provided.
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Diagnostics;
namespace SparseRanges
{
#region Structs
struct FILE_ZERO_DATA_INFORMATION
{
public long offset;
public long zero;
}
struct FILE_ALLOCATED_RANGE_BUFFER
{
public long offset;
public long length;
}
#endregion
class Program
{
#region Const ints
const uint FSCTL_SET_SPARSE = 590020;
const uint FSCTL_QUERY_ALLOCATED_RANGES = 606415;
#endregion
[DllImport("kernel32.dll", SetLastError = true)]
extern static bool GetVolumeInformation(string vol, StringBuilder name, int nameSize, out uint serialNum, out uint maxNameLen, out uint flags, StringBuilder fileSysName, int fileSysNameSize);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool DeviceIoControl([In] SafeFileHandle hDevice, [In] uint dwIoControlCode, IntPtr lpInBuffer, [In] int nInBufferSize, IntPtr lpOutBuffer, [In] int nOutBufferSize, ref uint lpBytesReturned, [In] IntPtr lpOverlapped);
public static bool GetSparseRange(SafeFileHandle hdrive, in FILE_ALLOCATED_RANGE_BUFFER query, ref FILE_ALLOCATED_RANGE_BUFFER[] response, int count)
{
int nInBufferSize = (int)Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER));
IntPtr lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
Marshal.StructureToPtr(query, lpInBuffer, true);
int nOutBufferSize = nInBufferSize * count;
IntPtr lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
uint bytesread = 0;
bool rc = DeviceIoControl(hdrive, FSCTL_QUERY_ALLOCATED_RANGES, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, ref bytesread, IntPtr.Zero);
int error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(lpInBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
return rc;
}
private static void PrintSparseRange(FILE_ALLOCATED_RANGE_BUFFER range)
{
Console.WriteLine("{0:d} offset, length = {1:d}", range.offset, range.length);
}
static void Main(string[] args)
{
uint temp1, temp2, flags, bytes=0;
if (GetVolumeInformation("C:\\", null, 0, out temp1, out temp2, out flags, null, 0))
{
uint supports_sparse = flags & 0x40;
if (supports_sparse == 0x40)
{
Console.WriteLine("Volume supports sparse files...");
string sparse_filename = Path.GetTempFileName();
System.IO.FileStream f = System.IO.File.Create(sparse_filename);
if (DeviceIoControl(f.SafeFileHandle, FSCTL_SET_SPARSE, IntPtr.Zero, 0, IntPtr.Zero, 0, ref bytes, IntPtr.Zero))
{
Console.WriteLine("Successfully generated a sparse file.");
f.SetLength(10240);
FILE_ALLOCATED_RANGE_BUFFER[] response = new FILE_ALLOCATED_RANGE_BUFFER[64];
FILE_ALLOCATED_RANGE_BUFFER query;
query.length = 10240;
query.offset = 0;
int count = 64;
if(GetSparseRange(f.SafeFileHandle, query, ref response, count))
{
Action<FILE_ALLOCATED_RANGE_BUFFER> print_all = new Action<FILE_ALLOCATED_RANGE_BUFFER>(PrintSparseRange);
Array.ForEach(response, print_all);
}
f.Close();
Console.WriteLine("Removing temp sparse file.");
File.Delete(sparse_filename);
}
}
}
}
}
}
BobZscharnagk wrote: The SafeFileHandle was created like this ...
using (dd = new FileStream(path + ".dd", FileMode.Open, FileAccess.Write, FileShare.Write)) Any particular reason why you are opening the file without Read access?
Best Wishes,
-David Delaune
|
|
|
|
|
Radnor,
Thanks for the reply and the time. When I tried your code, unmodified, i just get 64 lines of "0 offset, length = 0", which is because I think you didn't copy the Marshall'd response back into the passed response. I added two lines to your code...
f.SetLength(10240);
f.Write(new byte[] { (byte)'H', (byte)'e', (byte)'l', (byte)'l', (byte)'o' }, 0, 5);
and
int error = Marshal.GetLastWin32Error();
Marshal.PtrToStructure(lpOutBuffer, response);
Adding f.Write by itself should cause one of the blocks to be allocated and not show in the output. Testing with just this line gives the same result as if the write wasn't there.
Adding the second change, Marshal.PtrToStructure, causes an error "Quote: System.ArgumentException: 'The specified structure must be blittable or have layout information.
Which I think is where I started.
|
|
|
|
|
Finally got it working....
public static int GetSparseRange(SafeFileHandle hdrive, in FILE_ALLOCATED_RANGE_BUFFER query, ref FILE_ALLOCATED_RANGE_BUFFER[] response, out int count)
{
int nInBufferSize = Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER));
IntPtr lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
Marshal.StructureToPtr(query, lpInBuffer, false);
uint bytesreturned = 0, command = (uint)EIOControlCode.FsctlQueryAllocatedRanges;
int nOutBufferSize = nInBufferSize * 1024;
IntPtr lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
DeviceIoControl(
hdrive,
(uint)command,
lpInBuffer, (uint)nInBufferSize,
lpOutBuffer, (uint)nOutBufferSize,
out bytesreturned,
IntPtr.Zero);
int rc = Marshal.GetLastWin32Error();
count = (int)bytesreturned / nInBufferSize;
for (int j = 0; j < count; ++j)
{
response[j] = (FILE_ALLOCATED_RANGE_BUFFER)Marshal.PtrToStructure(lpOutBuffer + (j * nInBufferSize), typeof(FILE_ALLOCATED_RANGE_BUFFER));
}
Marshal.FreeHGlobal(lpInBuffer);
Marshal.FreeHGlobal(lpOutBuffer);
return rc;
}
|
|
|
|
|
Yep.
In my code sample I gave you you can add:
for (int i = 0; i < count; i++)
{
IntPtr ptr= new IntPtr(lpOutBuffer.ToInt64() + i * Marshal.SizeOf(typeof(FILE_ALLOCATED_RANGE_BUFFER)));
response[i] = Marshal.PtrToStructure<FILE_ALLOCATED_RANGE_BUFFER>(ptr);
}
Under the call to DeviceIoControl to marshal the unmanaged array.
I am a Windows API guy... I got involved to help you figure out why DeviceIoControl was giving you an ERROR_ACCESS_DENIED . Didn't know I would need to fix your C# code too.
Glad you got it working, good luck.
Best Wishes,
-David Delaune
|
|
|
|
|
Hi, folks.
I created a user control with some properties and methods and used it in a Forms project where it appears many times. It's working fine.
But now I decided to improve some characteristics and I eliminated some properties and added some.
The problem is that the forms where this control appears show errors and it' very difficult to open the form. After I open the form I removed the old control and tried to add the new version, but it appears that only the old version is accepted.
What is the best way to substitute a control under these circumstances?
I use C# in Visual Studio 2019.
Thanks.
|
|
|
|
|
The problem is probably that as you say:
Quote: I eliminated some properties and added some.
If any of the classes that use your control are referencing those properties, the new version will just not work: the properties no longer exist.
The proper way to do that is to depreciate the properties, not remove them: that way they can still be used but there is a warning that they shouldn't be used in new projects.
That is documentation only, however - for later versions, you can make them actually obsolete: ObsoleteAttribute Class (System) | Microsoft Docs[^] but you should allow a good time for people to migrate to the newer version before that happens.
Often, a more developer friendly way to do this with drastic changes is to end support for the existing version, and develop a new version for future projects.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Make the properties obsolete? I'll read more about.
Thanks.
|
|
|
|
|
You're welcome!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Member 14792393 wrote: I decided to improve some characteristics and I eliminated some properties and added some. A key question is what you did to the Forms that had instances of the UserControl that used the removed Properties: of course any attempted use/access of/to removed "anything" results in compile errors.Member 14792393 wrote: After I open the form I removed the old control and tried to add the new version, but it appears that only the old version is accepted This just doesn't make sense: did you edit the form code to remove any code that used the UserControl instance, and, then, re-build the Project/Solution? Did you re-build the solution after adding the new version of the UserControl?
There is (imho) a defect in Visual Studio that has never been fixed: you can modify a UserControl ... for example, add some new Control to it ... and, the change doesn't appear in currently open design-time Form Windows even after you re-build the solution. However, if you close the designer window, and re-open it: the view has been updated.
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
"did you edit the form code to remove any code that used the UserControl instance, and, then, re-build the Project/Solution? Did you re-build the solution after adding the new version of the UserControl?"
Yes, but the application is too big and has many instances of the control.
What I intend to do now is to rename the new version of the control and add it to the project. Then I open each form, erase the old version and insert the new version. After that I can remove the old version. It's a hard job, but I think it's the only way.
What do you think?
Thanks.
|
|
|
|
|
If you really have removed Properties you have to realize that those Properties perhaps are used by the Designer-Script of your Form.
So you must open the DesignerScript of your Form, find those part which assignes the Properties of this Control and delete those Assignments which are not more existent ...
|
|
|
|
|
good point from a slightly different angle
«One day it will have to be officially admitted that what we have christened reality is an even greater illusion than the world of dreams.» Salvador Dali
|
|
|
|
|
Maybe you're right. I'll take a look.
Thanks.
|
|
|
|
|
you will see it ...
And you are welcome ...
|
|
|
|
|
Here is some sample data i have been provided using json post
{
"PropertyInfos": [
{
"Identification": {
"IDValue": "102"
},
"PropertyName": "Casa Bella",
"ManagementCompany": {
"ManagementCompanyName": "ACME Trusts",
"Identification": {
"IDValue": "2"
}
},
"Address": {
"Address": "425 Slopestyle Skies Se",
"City": "Lincoln",
"State": "NE",
"PostalCode": "67123",
"Email": "test@example.com"
}
},
{
"Identification": {
"IDValue": "20"
},
"PropertyName": "Tall Tower",
"ManagementCompany": {
"ManagementCompanyName": "ACME Trusts",
"Identification": {
"IDValue": "2"
}
},
"Address": {
"Address": "789 Steele Street",
"City": "Denver",
"State": "CO",
"PostalCode": "80206",
"Email": "tall.tower@example.com"
}
},
{
"Identification": {
"IDValue": "92"
},
"PropertyName": "Z Emerson",
"ManagementCompany": {
"ManagementCompanyName": "ACME Trusts",
"Identification": {
"IDValue": "2"
}
},
"Address": {
"Address": "2199 112th St S",
"City": "Chicago",
"State": "IL",
"PostalCode": "60444",
"Email": "test@example.com"
}
}
]
}
How can I convert this into a list or dictionary so i can then work with each of the entries and import them into my system using c#. if they were in a list or dictionary i would be able to go through the list and do what i need with each data entry. I am very new when it comes to working with JSON api and what not. Any help or pointers in the right direction would be awesome. Thank you guys! 
|
|
|
|
|
Why not do what JSON is meant to do and convert it to classes? You can then use the classes directly in your code instead of trying to manually process the hierarchical data.
It's even easy to do: paste the JSON into your C# app in VS using "Paste special...Paste JSON as Classes" and VS will create the classes it represents for you. You can then use a JSON reader (I use Newtonsoft JSON.NET[^]) to process the JSON string and give you the filled out class data.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
 Lol im completely new to JSON so sorry for not knowing exactly what its supposed to do Heres the code to convert it to classes. I used quicktype.io to help me
<pre>
namespace quicktype
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class Welcome
{
[JsonProperty("PropertyInfos")]
public List<PropertyInfo> PropertyInfos { get; set; }
}
public partial class PropertyInfo
{
[JsonProperty("Identification")]
public Identification Identification { get; set; }
[JsonProperty("PropertyName")]
public string PropertyName { get; set; }
[JsonProperty("ManagementCompany")]
public ManagementCompany ManagementCompany { get; set; }
[JsonProperty("Address")]
public Address Address { get; set; }
}
public partial class Address
{
[JsonProperty("Address")]
public string AddressAddress { get; set; }
[JsonProperty("City")]
public string City { get; set; }
[JsonProperty("State")]
public string State { get; set; }
[JsonProperty("PostalCode")]
[JsonConverter(typeof(ParseStringConverter))]
public long PostalCode { get; set; }
[JsonProperty("Email")]
public string Email { get; set; }
}
public partial class Identification
{
[JsonProperty("IDValue")]
[JsonConverter(typeof(ParseStringConverter))]
public long IdValue { get; set; }
}
public partial class ManagementCompany
{
[JsonProperty("ManagementCompanyName")]
public string ManagementCompanyName { get; set; }
[JsonProperty("Identification")]
public Identification Identification { get; set; }
}
public partial class Welcome
{
public static Welcome FromJson(string json) => JsonConvert.DeserializeObject<Welcome>(json, quicktype.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this Welcome self) => JsonConvert.SerializeObject(self, quicktype.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
}
Now ive created a class in c# where i can access these classes. How do i get JSON to put my POST data into these classes. Or are you able to point me to a video, guide, etc that could help me learn this
|
|
|
|
|
As I said, I prefer Newtonsoft, so follow the link in my original response, and it'll show you how to deserialize it. It's only one line of code!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
|
There is a requirement to send and receive data over TCP/IP with a Fiscal (tax) device which acts as a gateway to the Tax authority server.
The application runs on c#.
Can anyone suggest suitable c# libraries which can be used for this purpose?
The data is to be packaged in JSON format.
Any help would be very much appreciated.
|
|
|
|
|
|