When defining Windows API const values, is it better to have them as const
public const int SW_HIDE = 0;
public const int SW_SHOWNORMAL = 1;
public const int SW_NORMAL = 1;
public const int SW_SHOWMINIMIZED = 2;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_MAXIMIZE = 3;
public const int SW_SHOWNOACTIVATE = 4;
public const int SW_SHOW = 5;
public const int SW_MINIMIZE = 6;
public const int SW_SHOWMINNOACTIVE = 7;
public const int SW_SHOWNA = 8;
public const int SW_RESTORE = 9;
public const int SW_SHOWDEFAULT = 10;
public const int SW_MAX = 10;
[DllImport( "user32.dll" )]
public static extern bool ShowWindow( HandleRef hWnd, int nCmdShow );
or to group them together as an enum.
public enum SW {
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
[DllImport( "user32.dll" )]
public static extern bool ShowWindow( HandleRef hWnd, SW nCmdShow );
Group them as enums.
Why? Ints are used all over the place and you can pass them where, for example, a size is necessary as well.. That led to the frickin hungarian notation (szSomething..) in the first place. The type system was lacking and they tried to "fix" it using the variable naming scheme. You're now better off, with a better type system; use it.
Define enums, group them in a sensible way and you won't Thread.Sleep(WM_User) someday (Yes, I'm not completely serious with this example, but I think you get the point).
Except for code maintainability, it doesn't matter at all.
I recommend using an enum; this allows you to use IntelliSense when calling the function, and can help prevent mistakes.
However, you should give your enum a meaningful name, such as WindowShowType.
Also, you might want to remove the prefixes, and perhaps standardize the names to CamelCase.
Related
I'm attempting to pass a uint array into the NVML function nvmlDeviceGetAccountingPids(Doc here) from C#, here's a minimum working sample of what I have so far:
{
public const string NVMLDLL = "nvml.dll";
public static class Constants
{
public const int NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE = 16;
public const int NVML_DEVICE_NAME_BUFFER_SIZE = 64;
public const int NVML_DEVICE_NAME_V2_BUFFER_SIZE = 96;
public const int NVML_DEVICE_PART_NUMBER_BUFFER_SIZE = 80;
public const int NVML_DEVICE_SERIAL_BUFFER_SIZE = 30;
public const int NVML_DEVICE_UUID_BUFFER_SIZE = 80;
public const int NVML_DEVICE_UUID_V2_BUFFER_SIZE = 96;
public const int NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE = 32;
public const int NVML_SYSTEM_DRIVER_VERSION_BUFFER_SIZE = 80;
public const int NVML_SYSTEM_NVML_VERSION_BUFFER_SIZE = 80;
public const int NVML_INIT_FLAG_NO_ATTACH = 2;
public const int NVML_INIT_FLAG_NO_GPUS = 1;
}
public enum nvmlReturn_t
{
NVML_SUCCESS = 0, // The operation was successful.
NVML_ERROR_UNINITIALIZED = 1, // NVML was not first initialized with nvmlInit().
NVML_ERROR_INVALID_ARGUMENT = 2, // A supplied argument is invalid.
NVML_ERROR_NOT_SUPPORTED = 3, // The requested operation is not available on target device.
NVML_ERROR_NO_PERMISSION = 4, // The current user does not have permission for operation.
NVML_ERROR_ALREADY_INITIALIZED = 5, // Deprecated: Multiple initializations are now allowed through ref counting.
NVML_ERROR_NOT_FOUND = 6, // A query to find an object was unsuccessful.
NVML_ERROR_INSUFFICIENT_SIZE = 7, // An input argument is not large enough.
NVML_ERROR_INSUFFICIENT_POWER = 8, // A device's external power cables are not properly attached.
NVML_ERROR_DRIVER_NOT_LOADED = 9, // NVIDIA driver is not loaded.
NVML_ERROR_TIMEOUT = 10, // User provided timeout passed.
NVML_ERROR_IRQ_ISSUE = 11, // NVIDIA Kernel detected an interrupt issue with a GPU.
NVML_ERROR_LIBRARY_NOT_FOUND = 12, // NVML Shared Library couldn't be found or loaded.
NVML_ERROR_FUNCTION_NOT_FOUND = 13, // Local version of NVML doesn't implement this function.
NVML_ERROR_CORRUPTED_INFOROM = 14, // infoROM is corrupted
NVML_ERROR_GPU_IS_LOST = 15, // The GPU has fallen off the bus or has otherwise become inaccessible.
NVML_ERROR_RESET_REQUIRED = 16, // The GPU requires a reset before it can be used again.
NVML_ERROR_OPERATING_SYSTEM = 17, // The GPU control device has been blocked by the operating system/cgroups.
NVML_ERROR_LIB_RM_VERSION_MISMATCH = 18, // RM detects a driver/library version mismatch.
NVML_ERROR_IN_USE = 19, // An operation cannot be performed because the GPU is currently in use.
NVML_ERROR_MEMORY = 20, // Insufficient memory.
NVML_ERROR_NO_DATA = 21, // No data.
NVML_ERROR_VGPU_ECC_NOT_SUPPORTED = 22, // The requested vgpu operation is not available on target device, becasue ECC is enabled.
NVML_ERROR_INSUFFICIENT_RESOURCES = 23, // Ran out of critical resources, other than memory.
NVML_ERROR_FREQ_NOT_SUPPORTED = 24, // Ran out of critical resources, other than memory.
NVML_ERROR_UNKNOWN = 999 // An internal driver error occurred.
}
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlInit_v2();
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlShutdown();
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetCount_v2(out uint deviceCount);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetHandleByIndex_v2(int index, out IntPtr handle);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetName(IntPtr device, [MarshalAs(UnmanagedType.LPStr)] StringBuilder deviceName, uint length);
[DllImport(NVMLDLL)]
private static extern nvmlReturn_t nvmlDeviceGetAccountingPids(IntPtr device, ref uint count, [In, Out] uint[] pids);
static void Main(string[] args)
{
if (nvmlInit_v2() == nvmlReturn_t.NVML_SUCCESS)
{
nvmlDeviceGetCount_v2(out uint deviceCount);
for (int i = 0; i < deviceCount; i++)
{
StringBuilder name = new();
nvmlDeviceGetHandleByIndex_v2(i, out IntPtr _device);
nvmlDeviceGetName(_device, name, Constants.NVML_DEVICE_NAME_V2_BUFFER_SIZE);
// arbitrary number for now
uint count = 5;
uint[] pids = new uint[count];
nvmlDeviceGetAccountingPids(_device, ref count, pids);
foreach(uint ui in pids) Console.WriteLine(ui);
}
nvmlShutdown();
}
}
}
and so far it's returning the correct # of processes that are utilizing the gpu, but the PID array keeps returning all 0's. I'm not particularly experienced with C# so if someone could show me the proper syntax for this(or lemme know if I have to resort to IntPtr's), the original function has this signature:
nvmlReturn_t nvmlDeviceGetAccountingPids ( nvmlDevice_t device, unsigned int* count, unsigned int* pids )
Parameters
device
The identifier of the target device
count
Reference in which to provide the pids array size, and to return the number of elements ready to be queried
pids
Reference in which to return list of process ids
If anyone knows that magic combo I'd sure appreciate it, thank you for your time =)
Sometimes I think I only type things to work them out ^_^
static void Main(string[] args)
{
if (nvmlInit_v2() == nvmlReturn_t.NVML_SUCCESS)
{
nvmlDeviceGetCount_v2(out uint deviceCount);
for (int i = 0; i < deviceCount; i++)
{
StringBuilder name = new();
nvmlDeviceGetHandleByIndex_v2(i, out IntPtr _device);
nvmlDeviceGetName(_device, name, Constants.NVML_DEVICE_NAME_V2_BUFFER_SIZE);
// arbitrary number for now
uint count = 0;
nvmlDeviceGetAccountingPids(_device, ref count, null);
uint[] pids = new uint[count];
if (nvmlDeviceGetAccountingPids(_device, ref count, pids) == nvmlReturn_t.NVML_SUCCESS)
{
foreach (uint ui in pids) Console.WriteLine(ui);
}
}
nvmlShutdown();
}
so it turns out that when passing the count to the function it wants the same number as the size of the array in order to populate the pids list(which makes sense I suppose). This is retrieved by just setting count to "0" and passing a null array to the function and it will set count to the size of the array. Create a new uint array with that size, pass the array/count and BAM, it returns the pids as desired.
Thanks for reading SO!
If anyone has some constructive criticism in terms of syntax/practices please do comment so I can improve this code as I go. Have a wonderful day 👍
I am trying to do login in the phone. I am developing in c# and the library is in C++. The function "lineDevSpecific" returns the value "-2147483595", but it must to be positive.
[DllImport("Tapi32.dll", SetLastError = true)]
unsafe private static extern int lineDevSpecific(IntPtr hLine, IntPtr lpParams);
[StructLayout(LayoutKind.Sequential)]
public struct UserRec
{
//[MarshalAs(UnmanagedType.I4)]
public int dwMode=8;
public int dwParam1=201;
public int dwParam2=0;
}
unsafe static void Iniciar()
{
string vline = "Ip Office Phone: 201";
IntPtr hline = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(vline);
var sizeUserRec = Marshal.SizeOf(typeof(UserRec));
var userRec = Marshal.AllocHGlobal(sizeUserRec);
int result=lineDevSpecific(hline, userRec);
var x = (UserRec)Marshal.PtrToStructure(userRec, typeof(UserRec));
Marshal.FreeHGlobal(userRec);
}
Version 2:
I have modified the initial post adding the lineInitializeEx method and lineOpen.
These methods returns a positive value, after this lineDevSpecific continues returning the same value.
[DllImport("Tapi32.dll", CharSet = CharSet.Auto)]
unsafe private static extern long lineInitializeEx(ref uint lphLineApp, uint hInstance, uint lpfnCallback, uint lpszFriendlyAppName, ref uint lpdwNumDevs, ref uint lpdwAPIVersion, ref uint lpLineInitializeExParams);
[DllImport("Tapi32.dll", SetLastError = true)]
internal static extern long lineOpen(ref uint hLineApp, uint dwDeviceID, uint lphLine, uint dwAPIVersion, uint dwExtVersion, uint dwCallbackInstance, uint dwPrivileges, uint dwMediaModes, ref uint lpCallParams);
[DllImport("Tapi32.dll", CharSet = CharSet.Auto)]
unsafe private static extern int lineDevSpecific(uint hLine, IntPtr lpParams);
uint lineApp = 0;
uint numdevs = 0;
uint apiversion = 0;
uint exparams = 0;
uint lpcallparams = 0;
string sParams = "";
long lSize = 0;
long inicio = lineInitializeEx(ref lineApp, 0, 0, 0, ref numdevs, ref apiversion, ref exparams);
if (inicio > 0)
{
long open = lineOpen(ref lineApp, 0, 0, 0, 0, 0, 0, 0, ref lpcallparams);
//string vline = "Ip Office Phone: 201";
//IntPtr hline = System.Runtime.InteropServices.Marshal.StringToHGlobalAnsi(vline);
var sizeUserRec = Marshal.SizeOf(typeof(UserRec));
var userRec = Marshal.AllocHGlobal(sizeUserRec);
int result = lineDevSpecific(lineApp, userRec);
var x = (UserRec)Marshal.PtrToStructure(userRec, typeof(UserRec));
Marshal.FreeHGlobal(userRec);
}
Solution: I have called to Julmar Atapi.
string extension = "201";
char[] c = new char[extension.Length + 2];
c[0] = (char)0x08; //login character
int i = 1;
foreach (char s in extension)
{
c[i] = s;
i++;
}
c[i] = (char)0x00; //null terminator
CurrentAddress.DeviceSpecific(Encoding.ASCII.GetBytes(c));
That is a LINEERR_ constant, see MSDN LINEERR_ Constants page
These use a hexadecimal unsigned "0x8000 00xx" style, turning them negative if you look at them as a signed int.
So this one is 0x8000 0035 LINEERR_INVALPOINTER
Your hline is wrong, this is a handle to a line not a text in a pointer. You need to get it from a lineOpen
Update for version 2
You are mixing up hLineApp and hLine. From lineOpen MSDN:
hLineApp: Handle to the application's registration with TAPI.
lphLine: Pointer to an HLINE handle that is then loaded with the handle representing the opened line device. Use this handle to identify the device when invoking other functions on the open line device.
In order to execute external applications from Silverlight app, you need to:
Run out-of-browser
Have elevated trust permissions
To execute such applications, you can do something like this
public static void EjecutaEXE(string ruta)
{
using (dynamic shell = AutomationFactory.CreateObject("WScript.Shell"))
{
shell.Run(#ruta);
}
}
I have found that I am only able to run such application from the Windows directory, Am I missing something? seems pointless such limitation.
This WORKS:
EjecutaEXE("C:/Windows/myAwesomeApp.exe")
This does NOT WORK:
EjecutaEXE("C:/myfolder/myAwesomeApp.exe")
There are no errors or exceptions, it just does nothing.
I have no experience With the code you presented, but as an alternative this should work:
public enum ShowCommands : int
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
SW_MAX = 11
}
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd,
string lpOperation,
string lpFile,
string lpParameters,
string lpDirectory,
ShowCommands nShowCmd);
public static void ExecuteMyCode(string filePath)
{
IntPtr retval = ShellExecute(System.IntPtr.Zero, string.Empty, filePath, string.Empty, string.Empty, ShowCommands.SW_NORMAL);
}
I have make a dll from dev c++.and I want to call the function.
the dev c++ code like this :
//the head file
struct sAdd
{
int* aarr;
int* barr;
int length;
};
DLLIMPORT int AddStruct (struct sAdd*);
//the c file
DLLIMPORT int AddStruct (struct sAdd* sadd)
{//sum the aarr and the barr and return the result.
int sum=0;
int* aarr=sadd->aarr;
int* barr=sadd->barr;
int numArr=sadd->length;
int i;
for(i=0;i<numArr;i++)
sum+=*(aarr+i);
i=0;
for(i=0;i<numArr;i++)
sum+=*(barr+i);
return sum;
}
In order to call the AddStruct function,I need to define a struct first.
public struct sAdd
{
public int[] a;
public int[] b;
public int length;
}
[DllImport("DllMain.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int AddStruct(ref sAdd sadd);
the code to call the AddStruct function is like this:
sAdd sadd = new sAdd();
sadd.a = new int[4] { 1, 2, 3 ,4};
sadd.b = new int[4] { 1, 2, 3 ,4};
sadd.length=4;
Console.WriteLine("sAdd:" + AddStruct(ref sadd).ToString());
the result should be 20,but I get a 37109984 or some other big number.
So ,I am not sure how to change the code to get a right reusult.Maybe I need to use the IntPtr or other ways??thanks .
At last,I deal with the problem.Just modify the code in c#.
[StructLayout(LayoutKind.Sequential)]
public struct sAdd
{
public IntPtr a;
public IntPtr b;
public int length;
};
sAdd sadd = new sAdd();
int[] a = new int[4] { 1, 2, 3 ,4};
int[] b = new int[4] { 1, 2, 3 ,4};
sadd.length = 4;
sadd.a = Marshal.UnsafeAddrOfPinnedArrayElement(a, 0);
sadd.b = Marshal.UnsafeAddrOfPinnedArrayElement(b, 0);
Console.WriteLine("sAdd:" + DllMainWrapper.AddStruct(ref sadd).ToString());
Your C code is broken.
You cannot compute the length of an array using sizeof when all you have is a pointer to the first element. You can only do so when you have a "real" array declaration in scope.
So this:
int* aarr=sadd->aarr;
int* barr=sadd->barr;
int numAarr=sizeof(aarr)/sizeof(int);
int numBarr=sizeof(barr)/sizeof(int);
is broken, numArr will be a constant value (1 if your pointer size is the same as your integer size, otherwise probably 2 on a 64-bit system with 32-bit int).
I have a simple C# data structure with a string, an int and a vector of ints:
class MyManagedClass
{
public string m_Str;
int m_Int;
int[] m_IntArray;
}
The equivalent in C++ is:
struct myUnmanagedStruct
{
char* m_Str;
UINT m_Int;
UINT* m_IntArray;
}
I have an unmanaged function that creates an array of myUnmanagedStruct structs. What is the best way to write a managed wrapper that correctly marshals the data such that what is created on the unmanaged side is correctly passed back to the managed side? (i.e. I want to make an array of MyManagedClass objects from an array of MyUnmanagedStructs)
Note:
a) A string is created in the unmanaged struct
b) A vector of ints is created in the unmanaged struct
My best attempt so far is:
On the managed side:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack=1)]
public class MyManagedClass
{
public MyManagedClass()
{
m_IntArray = new int[4];
}
public String m_Str;
public int m_Int;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public int[] m_IntArray;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnsafeLCEArray
{
public int m_Int;
public IntPtr m_CharBuf;
public IntPtr m_IntBuf;
}
public unsafe class LibWrap
{
// Declares managed prototypes for the unmanaged function.
[DllImport("mydll.dll", EntryPoint = "GetUnmanagedStructs")]
public static extern voidGetUnmanagedStructs(out int size, out IntPtr outArray);
}
On the unmanaged side:
typedef struct _MyUnmanagedStruct
{
char* m_Str;
UINT m_Int;
UINT* m_IntArray;
} MyUnmanagedStruct;
typedef struct _UNSAFELCEARRAY
{
char* strBuf;
UINT intBuf;
UINT* intArrayBuf;
} UNSAFELCEARRAY;
extern "C" __declspec(dllexport) void GetUnmanagedStructs( int* pSize, UNSAFELCEARRAY** ppStruct )
{
const int cArraySize = 5;
*pSize = cArraySize;
int numBytes = cArraySize * sizeof( MyUnmanagedStruct);
*ppStruct = (UNSAFELCEARRAY*)CoTaskMemAlloc(numBytes);
UNSAFELCEARRAY* pCurStruct = *ppStruct;
char* typenamebuffer;
char* numBuffer;
int var = 999;
for( int i = 0; i < cArraySize; i++, pCurStruct++ )
{
pCurStruct->intBuf = i+1;
typenamebuffer = (char*)CoTaskMemAlloc( 8 );
memcpy_s(typenamebuffer, 8, "bufABCD", 8);
pCurStruct->strBuf = typenamebuffer;
numBuffer = (char*)CoTaskMemAlloc( 16 );
++var;
memcpy_s(numBuffer, 4, &var, 4);
++var;
memcpy_s(numBuffer+4, 4, &var, 4);
++var;
memcpy_s(numBuffer+8, 4, &var, 4);
++var;
memcpy_s(numBuffer+12, 4, &var, 4);
pCurStruct->intArrayBuf = (UINT*)numBuffer;
}
}
Everything works if I remove the vector of ints from the managed and unmanaged objects, but with the code above the array of ints is uninitialized on return. I use the function below to generate MyManagedClasses from MyUnmanagedStructs
int size;
IntPtr outArray;
LibWrap.GetUnmanagedStructs(out size, out outArray);
manArray = new MyManagedClass[size];
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
manArray[i] = new MyManagedClass();
Marshal.PtrToStructure(current, manArray[i]);
Marshal.DestroyStructure(current, typeof(sb_LCE));
int numBytes = Marshal.SizeOf(manArray[i]);
current = (IntPtr)((long)current + numBytes);
}
Marshal.FreeCoTaskMem(outArray);
Forgive the lengthy explanation and the fact the unmanaged strut is being filled with dummy values. This is just for illustration.