I'm trying to move a folder from directory to another directory , but I'm getting an exception of access to path is denied , so I found a c++ SHFileOperation method that can be used in this case, the problem is that I didn't have any idea how to use it:
public void MoveFolder(string oldPath,string newPath)
{
SHFILEOPSTRUCT hFILEOPSTRUCT = new SHFILEOPSTRUCT();
hFILEOPSTRUCT.pFrom = oldPath;
hFILEOPSTRUCT.pTo = newPath;
int res = SHFileOperation(ref hFILEOPSTRUCT);
}
[DllImport("shell32.dll", CharSet = CharSet.Auto, SetLastError = true,
ThrowOnUnmappableChar = true)]
[Obsolete]
static extern int SHFileOperation(ref SHFILEOPSTRUCT lpFileOp);
Struct definition of SHFILEOPSTRUCT:
[Obsolete("Use this element with caution and only if you know what you are doing. It's only meant to be used internally by MahApps.Metro and Fluent.Ribbon. Breaking changes might occur anytime without prior warning.")]
public struct SHFILEOPSTRUCT
{
public IntPtr hwnd;
public FO wFunc;
public string pFrom;
public string pTo;
[CLSCompliant(false)]
public FOF fFlags;
public int fAnyOperationsAborted;
public IntPtr hNameMappings;
public string lpszProgressTitle;
}
}
This code throw an exception
Cannot marshal field 'fAnyOperationsAborted' of type 'ControlzEx.Standard.SHFILEOPSTRUCT': Invalid managed/unmanaged type combination (Int32/UInt32 must be paired with I4, U4, or Error).
How can I make this works?
Related
How do native methods initialize structures that they return through an out IntPtr parameter?
Given the following native code:
[DllImport("foo.dll", EntryPoint = "bar", CallingConvention = CallingConvention.Cdecl)]
internal static extern int GetBars(out int count, out IntPtr output);
and the following struct definition:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public readonly record struct BarOut
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public readonly string FieldA;
[MarshalAs(UnmanagedType.U1)]
public readonly bool FieldB;
}
the managed implementation is able to make the native call and read all the structs found at the pointer.
The entire code base also works with regular structs such as:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public struct BarOut
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 21)]
public string FieldA;
[MarshalAs(UnmanagedType.U1)]
public bool FieldB;
}
I cannot find any documentation that describes how the structs are initialized and therefore I am not clear whether these two output definitions are safely equivalent where the only difference is the record is immutable.
Does substituting records in the codebase present any problems?
I need some simple file operations on a Linux machine, for a service installer.
The code is .NET 5.0.
My current version uses Process.Start() to execute shell commands to change the owner of files and directories and set permissions.
This is quite slow (I use asynchronous methods), especially compared to Windows equivalents.
I see libc accessible to call from .NET has methods chmod and chown, however it wants uid and gid parameters. My application doesn't know the ids, at least without using shell for it.
So far I got something like this:
const string LIBC = "libc";
[DllImport(LIBC, SetLastError = true)]
private static extern int chmod(string path, uint mode);
[DllImport(LIBC, SetLastError = true)]
private static extern int chown(string path, int owner, int group);
So... how to get those 2 ints required?
UPDATE
Why anyone see this question (especially considering its title) as duplicate of question about similar, yet different things.
I know how to change owner and permissions of Linux files in many ways. The easiest way is to use Linux shell. The quickest and easiest way is to use Mono.Posix.NETStandard library, that call libc internally.
My specific question is HOW IT IS MADE? HOW DOES IT WORK?
To be even more specific:
Here's the Linux manual page for getpwnam():
https://man7.org/linux/man-pages/man3/getpwnam.3.html
How to just call it from C# using p/invoke? I see in many examples, that when they replace char* with string it somehow magically works. I created a struct like this:
public struct PASSWD {
public string pw_name; /* username */
public string pw_passwd; /* user password */
public int pw_uid; /* user ID */
public int pw_gid; /* group ID */
public string pw_gecos; /* user information */
public string pw_dir; /* home directory */
public string pw_shell; /* shell program */
};
...and tried to use it as out parameter for the signature.
I get no error, but it just doesn't work. The struct I get is empty.
So again, we are using Platform Invoke, in C#, we are calling libc and we want to get results from a structure. As far as I googled - it's not google-able. There is only Mono source code, that uses external module that implements what I need. I suspect they made it for performance reasons, also - using some special tools, because in comments stands that the code is generated.
My question is again, how, using Linux manual page definition create appropriate method signature for C# to be able to extract those 2 integers from getpwnam().
I also was curious if something like that might already exist in .NET itself, but I guess it doesn't.
So, I got rusty with p/invoke. My issue was I forgot, that when native function returns a pointer to a structure, there is no automatic conversion, I have to leave pointer in signature, so:
[DllImport(LIBC, SetLastError = true)]
internal static extern IntPtr getgrnam(string name);
[DllImport(LIBC, SetLastError = true)]
internal static extern IntPtr getpwnam(string name);
internal struct Group {
public string Name;
public string Password;
public uint Gid;
public IntPtr Members;
}
internal struct Passwd {
public string Name;
public string Password;
public uint Uid;
public uint Gid;
public string GECOS;
public string Directory;
public string Shell;
}
Lets create fully managed .NET style types:
public sealed class GroupInfo {
public string Name { get; }
public uint Id { get; }
public string[] Members { get; }
internal GroupInfo(Syscall.Group group) {
Name = group.Name;
Id = group.Gid;
Members = GetMembers(group.Members).ToArray();
}
private static IEnumerable<string> GetMembers(IntPtr members) {
IntPtr p;
for (int i = 0; (p = Marshal.ReadIntPtr(members, i * IntPtr.Size)) != IntPtr.Zero; i++)
yield return Marshal.PtrToStringAnsi(p)!;
}
}
public class UserInfo {
public string Name { get; }
public uint Uid { get; }
public uint Gid { get; }
public string? Directory { get; }
public string? Shell { get; }
internal UserInfo(Syscall.Passwd passwd) {
Name = passwd.Name;
Uid = passwd.Uid;
Gid = passwd.Gid;
Directory = passwd.Directory;
Shell = passwd.Shell;
}
}
And it can be used like this:
public static UserInfo? GetUserInfo(string name) {
var result = Syscall.getpwnam(name);
if (result != IntPtr.Zero) return new UserInfo(Marshal.PtrToStructure<Syscall.Passwd>(result));
return null;
}
public static GroupInfo? GetGroupInfo(string name) {
var result = Syscall.getgrnam(name);
if (result != IntPtr.Zero) return new GroupInfo(Marshal.PtrToStructure<Syscall.Group>(result));
return null;
}
I kindly wanted to ask if it is recommendable to add properties for fields in a struct scope, if the struct is used for an winAPI call (f.ex. dllimport("xxx.dll")).
The question poped up when I let run the code Analysis - saying me, that I should use property accessors instead having public fields in struct.
And true, onthinking I would recommend that too, but - is an API call still possible with the 'so code optimized' struct?
May be I ought to show what I mean:
as everybody knows it:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct someAPICallStructure
{
public int cbSize;
public IntPtr hwndParent;
public string pszMessageText;
public string pszCaptionText;
public IntPtr hbmBanner;
}
as the code analyzer wishes:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct someAPICallStructure
{
public CBSize
{
get
{
return cbSize;
}
set
{
cbSize = value;
}
}
.... and properties for all other fields too ...
int cbSize;
IntPtr hwndParent;
string pszMessageText;
string pszCaptionText;
IntPtr hbmBanner;
}
Or could I even use like this?
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct someAPICallStructure
{
public CBSize {get; set;}
... and with all other fields too ...
}
And even further; can I add equals(..) and other suggested methods to the struct and it works still for the API Call?
I have a C# project that makes calls out to an unmanaged C++ dll. The wrapper and most of the calls are working OK, so I know that I have the basic structure of how everything ties together OK, but there is one specific call that is giving me fits. The API call requires a pointer to a structure, which contains a list of configuration data.
Here is the call:
m_status = m_XXXXBox.SetConfig(m_channelId, ref SCONFIG_LIST);
Where SCONFIG_LIST is the structure containing the data...
The issue specifically relates to SCONFIG_LIST
Here is the documentation directly from the spec for this API :
Points to the structure SCONFIG_LIST, which is defined as follows:
typedef struct
{
unsigned long NumOfParams; /* number of SCONFIG elements */
SCONFIG *ConfigPtr; /* array of SCONFIG */
} SCONFIG_LIST
where:
NumOfParms is an INPUT, which contains the number of SCONFIG elements in the array
pointed to by ConfigPtr.
ConfigPtr is a pointer to an array of SCONFIG structures.
The structure SCONFIG is defined as follows:
typedef struct
{
unsigned long Parameter; /* name of parameter */
unsigned long Value; /* value of the parameter */
} SCONFIG
Here are the 2 structures that I defined in C#:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig
{
public int Parameter;
public int Value;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig_List
{
public int NumOfParams;
// public List<SConfig> sconfig = new List<SConfig>(); // This throws compile time error
public List<SConfig> sconfig;
}
I know you can not have field initializers in structs, but I cant seem to figure out how to initialize the sconfig in the struct externally...
Here is snippet from the calling method
SConfig_List myConfig = new SConfig_List();
SConfig configData = new SConfig();
configData.Parameter = 0x04;
configData.Value = 0x10;
myConfig.NumOfParams = 1;
myConfig.sconfig.Add(configData);
This throws an error at runtime of "object reference not set to an instance of an object"
I understand this error because sconfig has not been initialized - I just cant figure out how to do that....
So my next thought was to get around this, I would just create the SCONFIG_LIST struct like this (without the list inside) - My reasoning for this is that I now do not have to initialize the object, and I could just make multiple calls to dll with a NumOfParams = 1, rather than NumOfParams > 1 and having the dll loop through the struct data.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct SConfig_List
{
public int NumOfParams;
public SConfig sconfig;
}
And here is how I called the method
configData.Parameter = 0x04;
configData.Value = 0x10;
myConfig.NumOfParams = 1;
myConfig.sconfig.Parameter = configData.Parameter;
myConfig.sconfig.Value = configData.Value;
m_status = m_XXXXBox.SetConfig(m_channelId, ref myConfig);
This got rid of the errors to this point, now on the the actual method that calls the dll
There are still several questions / issues surrounding the Marshalling, but here it is:
public XXXXErr SetConfig(int channelId, ref SConfig_List config)
{
unsafe
{
IntPtr output = IntPtr.Zero;
IntPtr input = Marshal.AllocHGlobal(Marshal.SizeOf(config));
Marshal.StructureToPtr(config, input, true);
XXXXErr returnVal = (XXXXErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);
return returnVal;
}
}
This gets past all of the initial setup without error, but when I try to actually invoke the dll I get an error : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
I know this is a mouthful, and I really don't even know exactly what to ask as I am sure there are multiple issues within this post, but any ideas on getting me on the right track?
I have tried so many things at this point I am at a loss, and I just need some direction. I am not looking for a "do this for me" type answer, but rather an explanation and maybe some pointers on getting this done. As with all things, I am sure there are multiple ways of accomplishing the task - maybe a way that works, but is not good form, and a longer more complicated way that may be "better practice"
Any and all suggestions / comments will be greatly appreciated. And if I excluded any relevant data that is required to help me solve this riddle let me know and I will provide what I can.
I want to thank the responses so far.
I have been trying every combination to try and resolve this myself but I have not had any luck so far. I have found quite a few ways that do NOT work, however :-)
I have tried various combinations of "unsafe" - "MarshalAs", "StructLayout" and several other things I found on the web, now I am begging for mercy.
I have successfully implemented several other calls to this unmanaged dll, but all of them use simple integer pointers etc. My problem is passing the pointer to a Struct containing an array of another struct. If you look at the very top of my original question you can see the documentation from the dll and how it wants thing structured. There is NO return value, I am merely trying to pass some configuration settings to a device through this dll.
I am going to post a framework of my entire project so that maybe I can get someone to hold my hand through this process, and hopefully help others in the future trying to solve this type of issue as well.
Here is skeleton of Wrapper (not all functions displayed)
using System;
using System.Runtime.InteropServices;
namespace My_Project
{
internal static class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
internal class APIDllWrapper
{
private IntPtr m_pDll;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int APIIoctl(int channelId, int ioctlID, IntPtr input, IntPtr output);
public APIIoctl Ioctl;
//extern āCā long WINAPI APIIoctl
//(
//unsigned long ChannelID,
//unsigned long IoctlID,
//void *pInput,
//void *pOutput
//)
public bool LoadAPILibrary(string path)
{
m_pDll = NativeMethods.LoadLibrary(path);
if (m_pDll == IntPtr.Zero)
return false;
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "APIIoctl");
if (pAddressOfFunctionToCall != IntPtr.Zero)
Ioctl = (APIIoctl)Marshal.GetDelegateForFunctionPointer(
pAddressOfFunctionToCall,
typeof(APIIoctl));
return true;
}
public bool FreeLibrary()
{
return NativeMethods.FreeLibrary(m_pDll);
}
}
}
And Here is the class that defines the hardware I am trying to communicate with
namespace My_Project
{
public class APIDevice
{
public string Vendor { get; set; }
public string Name { get; set; }
public override string ToString()
{
return Name;
}
}
}
Interface
using System.Collections.Generic;
namespace My_Project
{
public interface I_API
{
APIErr SetConfig(int channelId, ref SConfig_List config);
}
}
The actual Class containing the API Code - this is where the error is, I know that how I have the IntPtrs now is Not correct - But this displays what I am trying to do
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace My_Project
{
public class API : I_API
{
private APIDevice m_device;
private APIDllWrapper m_wrapper;
public APIErr SetConfig(int channelId, ref SConfig_List config)
{
IntPtr output = IntPtr.Zero;
IntPtr input = Marshal.AllocHGlobal(Marshal.SizeOf(config));
Marshal.StructureToPtr(config, input, true);
APIErr returnVal = (APIErr)m_wrapper.Ioctl(channelId, (int)Ioctl.SET_CONFIG, input, output);
return returnVal;
}
}
}
Here is class containing the definitions for the Structs I am using
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace My_Project
{
public enum APIErr
{
STATUS_NOERROR = 0x00,
ERR_BUFFER_EMPTY = 0x10,
ERR_BUFFER_FULL = 0x11,
ERR_BUFFER_OVERFLOW = 0x12
}
public struct SConfig
{
public int Parameter;
public int Value;
}
public struct SConfig_List
{
public int NumOfParams;
public SConfig[] sconfig;
public SConfig_List(List<SConfig> param)
{
this.NumOfParams = param.Count;
this.sconfig = new SConfig[param.Count];
param.CopyTo(this.sconfig);
}
}
}
And finally - the actual application calling the dll through the wrapper
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using My_Project;
namespace Test_API
{
public class Comm
{
private I_API m_APIBox;
APIErr m_status;
int m_channelId;
bool m_isConnected;
public Comm(I_API apiInterface)
{
m_APIBox = apiInterface;
m_isConnected = false;
m_status = APIErr.STATUS_NOERROR;
}
public bool ConfigureDevice()
{
SConfig tempConfig = new SConfig();
tempConfig.Parameter = 0x04;
tempConfig.Value = 0x10;
SConfig_List setConfig = new SConfig_List(tempConfig);
m_status = m_APIBox.SetConfig(m_channelId, ref setConfig);
if (m_status != APIErr.STATUS_NOERROR)
{
m_APIBox.Disconnect(m_channelId);
return false;
}
return true;
}
}
}
You cannot marshal List<>, it must be an array. An array is already marshaled as a pointer so you don't have to do anything special. Go easy on the Pack, no need for the unsafe keyword.
You could add a constructor to the struct to make it easy to initialize it from a List<>. Like this:
[StructLayout(LayoutKind.Sequential)]
public struct SConfig {
public int Parameter;
public int Value;
}
[StructLayout(LayoutKind.Sequential)]
public struct SConfig_List {
public int NumOfParams;
public SConfig[] sconfig;
public SConfig_List(List<SConfig> param) {
this.NumOfParams = param.Count;
this.sconfig = new SConfig[param.Count];
param.CopyTo(this.sconfig);
}
}
To initialize list you just have to add line:
myConfig.sconfig = new List<SConfig>()
before you start adding elements into it.
I started another thread because I was asking the wrong question due to my inexperience
The working solution is here
Marshal array of struct and IntPtr
Thanks for the help
-Lee
I'm using native functions and have small problem with marshaling structs in c#. I have pointer to struct in another struct - e.g. C# declarations:
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet = CharSet.Auto)]
public struct PARENT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string Name;
[MarshalAs(UnmanagedType.Struct, SizeConst=8)]
public CHILD pChild;
}
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet = CharSet.Auto)]
public struct CHILD
{
public UInt32 val1;
public UInt32 val2;
}
In PARENT struct I should have a pointer to CHILD struct. I need to pass a 'pointer to reference' (of PARENT struct) as argument of API function.
There's no problem with single reference ("ref PARENT" as argument of imported dll function) but how to pass "ref ref" ? Is it possible without using unsafe code (with C pointer) ?
greetings
Arthur
If you do not want to use unsafe code, then you need to define Child as IntPtr and add a property which access then the values from the Child IntPtr.
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet = CharSet.Auto)]
public struct PARENT
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string Name;
public IntPtr pChild;
public CHILD Child{
get {
return (CHILD)Marshal.PtrToStructure(pChild, typeof(CHILD));
}
}
}
[StructLayout(LayoutKind.Sequential, Pack=1, CharSet = CharSet.Auto)]
public struct CHILD
{
public UInt32 val1;
public UInt32 val2;
}
I think it is easier and cleaner with unsafe code/pointers.
This is a combination of safe and unsafe, as I believe is reasonable here.
fixed (void* pt = new byte[Marshal.SizeOf(myStructInstance)])
{
var intPtr = new IntPtr(pt);
Marshal.StructureToPtr(myStructInstance, intPtr, true);
// now "pt" is a pointer to your struct instance
// and "intPtr" is the same, but wrapped with managed code
}