EPPLUS throwing exception while using worksheet.Insertrow(int rowfrom, int rows, int startrowfrom) in .net core 3.1 app - .net-core-3.1

I am developing an webapp using .net core 3.1 and I am getting some EPPLUS EXCEPTION like "Invalid Address format APPID".
here is my error log:
2020-07-08T13:13:25.9386149-04:00 0HM13C84RA267:00000002 [ERR] Invalid Address format APPID (5598a7b8)
2020-07-08T13:13:26.3540346-04:00 0HM13C84RA267:00000002 [ERR] at OfficeOpenXml.ExcelCellBase.ThrowAddressException(String address, Int32& row, Int32& col, Boolean throwException)
at OfficeOpenXml.ExcelCellBase.GetRowCol(String address, Int32& row, Int32& col, Boolean throwException, Boolean& fixedRow, Boolean& fixedCol)
at OfficeOpenXml.ExcelCellBase.GetRowColFromAddress(String CellAddress, Int32& FromRow, Int32& FromColumn, Int32& ToRow, Int32& ToColumn, Boolean& fixedFromRow, Boolean& fixedFromColumn, Boolean& fixedToRow, Boolean& fixedToColumn)
at OfficeOpenXml.ExcelAddressBase.SetAddress(String address)
at OfficeOpenXml.ExcelNamedRangeCollection.Insert(Int32 rowFrom, Int32 colFrom, Int32 rows, Int32 cols, Func`2 filter, Int32 lowerLimint, Int32 upperLimit)
at OfficeOpenXml.ExcelNamedRangeCollection.Insert(Int32 rowFrom, Int32 colFrom, Int32 rows, Int32 cols, Int32 lowerLimint, Int32 upperLimit)
at OfficeOpenXml.Core.Worksheet.WorksheetRangeInsertHelper.InsertCellStores(ExcelWorksheet ws, Int32 rowFrom, Int32 columnFrom, Int32 rows, Int32 columns, Int32 columnTo)
at OfficeOpenXml.Core.Worksheet.WorksheetRangeInsertHelper.InsertRow(ExcelWorksheet ws, Int32 rowFrom, Int32 rows, Int32 copyStylesFromRow)
at OfficeOpenXml.ExcelWorksheet.InsertRow(Int32 rowFrom, Int32 rows, Int32 copyStylesFromRow)
at Api.Utility.ExcelHelper.abc(String templatePath, String targetFile, List`1 lstSmallDollarWriteoff, String userId, String userName, String monthYearFolder, Int64 eventLogId)
my code is like below :
using (ExcelPackage excelPackage = new ExcelPackage(new FileInfo(targetFile), new FileInfo(templatePath)))
{
int startRow = 13;
int counter = 1;
ExcelWorksheet objWorksheet = excelPackage.Workbook.Worksheets["Journal Entry"];
//Posting date
objWorksheet.Cells[8, 2].Value = DateTime.Now.ToString("MM/dd/yyyy");
var lstGroup = lstdata.GroupBy(x => new { x.Company, x.Currency, x.Division }).
Select(x => new { x.Key, Amount = x.Sum(y => y.Amount) });
int rows = lstdata.Count + lstGroup.Count();
int rowFrom=(startRow + 1);
objWorksheet.InsertRow( rowFrom, rows, startRow); //Here, for executing this, I am getting the exception
foreach (var item in lstGroup)
{
List<SettleData> lstSDataByKey = lstDataByKey.Where(x => x.Division == item.Key.Division && x.Company == item.Key.Company && x.Currency == item.Key.Currency).ToList();
foreach (SettleData keyItem in lstDataByKey)
{
CreateJetsEntry(ref startRow, ref counter, objWorksheet, keyItem);
}
}
excelPackage.Save();
}
}
I have used EPPLUS in my appsettings.json like below :
"EPPlus": {
"ExcelPackage": {
"LicenseContext": "Commercial"
}
},
Any leads will be appreciated. I am stuck in this for a while.

Related

How Do I PInvoke Into CommonCrypto CCKeyDerivationPBKDF?

I am attempting to PInvoke into the CCKeyDerivationPBKDF here.
The method signature looks like this:
int
CCKeyDerivationPBKDF( CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen,
const uint8_t *salt, size_t saltLen,
CCPseudoRandomAlgorithm prf, uint rounds,
uint8_t *derivedKey, size_t derivedKeyLen)
__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
Currently I am attempting this:
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static void CCKeyCerivationPBKDF(int algorithm, string password, int passwordLen,
string salt, int saltLen, int prf, int rounds, out byte[] derivedKey, int derivedKeyLength);
and am getting the error:
malloc: *** error for object 0xb9374fc61e8f9d1e: pointer being freed was not allocated
This is my first attempt to PInvoke something. I'm fairly certain that my signature is probably way off. What does it need to be?
You are getting the pointer being freed was not allocated error due to the out flag on the derivedKey parameter, just pass it as an IntPtr (byte[]) and Mono will marshall it correctly:
CCKeyCerivationPBKDF signature:
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static int CCKeyCerivationPBKDF(
int algorithm,
string password,
nint passwordLen,
string salt,
nint saltLen,
UInt32 prf,
int rounds,
byte[] derivedKey,
int derivedKeyLength);
Example:
var passwordEntry = "StackOverflow";
var saltEntry = "SaltyMcSalty";
var keyBytes = new byte[32 + 1];
Array.Clear(keyBytes, 0, keyBytes.Length);
var result = CCKeyCerivationPBKDF(2, passwordEntry, passwordEntry.Length, saltEntry, saltEntry.Length, 3, 1, keyBytes, keyBytes.Length);
Use "native" objects / reduced marshaling:
(Had to due it this way to get passed on a military/aerospace certification/review)
[DllImport(ObjCRuntime.Constants.libSystemLibrary, EntryPoint = "CCKeyDerivationPBKDF")]
public extern static int CCKeyCerivationPBKDF(
int algorithm,
IntPtr password,
nuint passwordLen,
IntPtr salt,
nuint saltLen,
UInt32 prf,
nuint rounds,
IntPtr derivedKey,
nuint derivedKeyLength);
Example (w/ Base64):
var passwordEntry = "StackOverflow";
var passwordBytes = System.Text.Encoding.UTF8.GetBytes(passwordEntry);
var passwordBase64 = Convert.ToBase64String(passwordBytes);
var passwordNSStringBase64 = new NSString(passwordBase64);
var passwordNSData = new NSData(passwordNSStringBase64, NSDataBase64DecodingOptions.None);
var saltEntry = "SaltyMcSalty";
var saltBytes = System.Text.Encoding.UTF8.GetBytes(saltEntry);
var saltBase64 = Convert.ToBase64String(saltBytes);
var saltNSStringBase64 = new NSString(saltBase64);
var saltNSData = new NSData(saltNSStringBase64, NSDataBase64DecodingOptions.None);
var keyBytes = new NSMutableData();
keyBytes.Length = 33;
var result = CCKeyCerivationPBKDF(2, passwordNSData.Bytes, passwordNSData.Length, saltNSData.Bytes, saltNSData.Length, 3, 1, keyBytes.MutableBytes, keyBytes.Length - 1);

Refreshing a folder that doesn't exist in the file system

In my shell extension I have folders that don't actually exist in the file system, but only appear so to the user.
When the content of those folders is changed, I want to refresh them, and currently I do it in the same method I do for regular folders:
Win32.SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Whereas PIDL is a list of shell folders IDs, as required by SHCNF_IDLIST.
The problem is that explorer doesn't handle my non existing folders. Instead of refreshing them, it sends me back to the root folder.
I know that I construct the PIDL correctly since this mechanism works for existing folders, as previously mentioned.
How can I override the handler to SHChangeNotify? Or is there a better way for calling refresh?
Edit:
How my PIDL is generated:
IntPtr GetPIDL(IFolderItem target)
{
Stack stack = new Stack(5);
IntPtr data = IntPtr.Zero;
byte[] rootPIDL = null;
IFolderItem curr = target;
while (curr != null)
{
if (curr.rootPIDL != null)
{
rootPIDL = curr.rootPIDL;
}
else
{
data = curr.SerializeInt();
stack.Push(data);
}
curr = curr.ParentFolder;
}
if (rootPIDL == null && stack.Count == 0)
return IntPtr.Zero;
object[] x = stack.ToArray();
IntPtr[] pidls = null;
int count = stack.Count;
if (count > 0)
{
pidls = new IntPtr[stack.Count];
for (int i = 0; i < count; i++)
{
pidls[i] = (IntPtr)stack.Pop();
}
}
return CreatePIDL(rootPIDL, pidls);
}
My CreatePIDL implementation:
internal unsafe static IntPtr CreatePIDL(byte[] rootPIDL,IntPtr[] pidls)
{
int headerSize = Marshal.SizeOf(typeof(ushort));
int totalSize = headerSize;
if (rootPIDL != null)
totalSize += rootPIDL.Length - headerSize;
if (pidls!=null && pidls.Length > 0)
{
foreach (IntPtr data in pidls)
{
totalSize += PIDLSize(data);
}
}
IntPtr ret = PIDLAlloc(totalSize);
IntPtr currPos = ret;
if(rootPIDL!=null)
{
Marshal.Copy(rootPIDL, 0, currPos, rootLPIFQ.Length - headerSize);
currPos = Win32.AdvancePtr(currPos, rootLPIFQ.Length - headerSize);
}
if (pidls != null && pidls.Length>0)
{
foreach (IntPtr data in pidls)
{
int dataLength = PIDLSize(data);
Win32.CopyMemory(currPos, data, dataLength);
currPos = Win32.AdvancePtr(currPos, dataLength);
}
}
Marshal.WriteInt16(currPos, (short)0);
return ret;
}
internal static unsafe int PIDLSize(IntPtr ptr)
{
return (int) (*((ushort*)ptr));
}
internal unsafe static IntPtr PIDLAlloc(int size)
{
IntPtr ret = Marshal.AllocCoTaskMem(size);
if (ret == IntPtr.Zero)
throw new OutOfMemoryException();
return ret;
}
I found a workaround. It is not pretty nor optimal, yet it works well.
Instead of calling the notify with SHCNE_UPDATEDIR, I'm executing all three of the following notifiers in sequence:
Win32.SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Win32.SHChangeNotify(SHCNE_CREATE, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);
Win32.SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST | SHCNF_FLUSH, PIDL, IntPtr.Zero);

Wrong LastLogon returned from Win32_NetworkLoginProfile

Using WMI Explorer (or any other tool), the LastLogon timestamp for my user is showing an outdated value instead of the current date (since I'm currently using this PC):
SELECT * FROM Win32_NetworkLoginProfile
--
LastLogon = 20150212180405.000000+120
At the same time, other domain users are listed with LastLogon as the current date, so this is an issue for my user only.
On the other hand, NetUsers is reporting the current date, as expected:
DOMAIN\user user name 2015/03/10 10:14
What is the cause of the WMI wrong result?
Environment: Win 7 x64, domain user added in the local admins group.
I had the pleasure of receiving an answer from an Optimum X developer of NetUsers.exe, extremely professional and very informative.
They made the program in c++ and the most reliable way to track login times was reading the LastWriteTime on the registry key of each profile located under "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
After I personally tried every class with WMI, they all failed me, and so I resorted to pInvoke for reading the hidden registry property "LastWriteTime" using C#
Here's the main function you'd call on a HKLM RegistryKey:
private static DateTime GetHKLMRegistryKeyLastWriteTime(RegistryKey key, string RemoteComputer)
{
DateTime LastWriteTime = DateTime.MinValue;
//set RegSAM access
RegSAM desiredSAM = RegSAM.Read;
//set key to same navigation (win32 vs win64)
if (key.View == RegistryView.Registry32)
{
desiredSAM |= RegSAM.WOW64_32Key;
}
else if(key.View == RegistryView.Registry64)
{
desiredSAM |= RegSAM.WOW64_64Key;
}
//Get Registry Hive Key on RemoteComputer.
UIntPtr computerRegHive = ConnectToRegistryHive(RemoteComputer, HKEY_LOCAL_MACHINE);
if(computerRegHive != UIntPtr.Zero)
{
string keyPath = key.Name;
int rootSeperatorIndex = keyPath.IndexOf(#"\");
if (rootSeperatorIndex != -1)
{
keyPath = keyPath.Substring(rootSeperatorIndex + 1, keyPath.Length - (rootSeperatorIndex + 1));
}
UIntPtr computerRegKey = OpenRegistrySubKey(computerRegHive, keyPath, desiredSAM);
//We no longer need computerRegHive, close!
RegCloseKey(computerRegHive);
if(computerRegKey != UIntPtr.Zero)
{
LastWriteTime = GetRegistryKeyLastWriteTime(computerRegKey);
//We no longer need computerRegKey, close!
RegCloseKey(computerRegKey);
}
}
return LastWriteTime;
}
And Here's the stuff you need to make it work:
public static uint HKEY_LOCAL_MACHINE = 0x80000002u;
[DllImport("advapi32.dll")]
private static extern int RegConnectRegistry(string lpmachineName, uint hKey, out UIntPtr phKResult);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
private static extern int RegOpenKeyEx(
UIntPtr hKey,
string subKey,
int ulOptions, //Set to 0
RegSAM samDesired, //Desired Access (win32/win64 & Read or ReadWrite)
out UIntPtr hkResult);
[DllImport("advapi32.dll")]
private static extern int RegQueryInfoKey(
UIntPtr hKey,
StringBuilder lpClass,
IntPtr lpcbClass,
IntPtr lpReserved,
IntPtr lpcSubKeys,
IntPtr lpcbMaxSubKeyLen,
IntPtr lpcbMaxClassLen,
IntPtr lpcValues,
IntPtr lpcbMaxValueNameLen,
IntPtr lpcbMaxValueLen,
IntPtr lpcbSecurityDescriptor,
[Out][Optional]out FILETIME lpftLastWriteTime
);
[DllImport("advapi32.dll")]
private static extern int RegCloseKey(UIntPtr hKey);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool FileTimeToSystemTime([In] ref FILETIME lpFileTime, out SYSTEMTIME lpSystemTime);
[Flags]
public enum RegSAM
{
QueryValue = 0x0001,
SetValue = 0x0002,
CreateSubKey = 0x0004,
EnumerateSubKeys = 0x0008,
Notify = 0x0010,
CreateLink = 0x0020,
WOW64_32Key = 0x0200,
WOW64_64Key = 0x0100,
WOW64_Res = 0x0300,
Read = 0x00020019,
Write = 0x00020006,
Execute = 0x00020019,
AllAccess = 0x000f003f
}
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public uint LowPart;
public uint HighPart;
};
[StructLayout(LayoutKind.Sequential, Pack = 2)]
public struct SYSTEMTIME
{
public ushort Year;
public ushort Month;
public ushort DayOfWeek;
public ushort Day;
public ushort Hour;
public ushort Minute;
public ushort Second;
public ushort Milliseconds;
public SYSTEMTIME(DateTime dt)
{
dt = dt.ToUniversalTime();
Year = Convert.ToUInt16(dt.Year);
Month = Convert.ToUInt16(dt.Month);
DayOfWeek = Convert.ToUInt16(dt.DayOfWeek);
Day = Convert.ToUInt16(dt.Day);
Hour = Convert.ToUInt16(dt.Hour);
Minute = Convert.ToUInt16(dt.Minute);
Second = Convert.ToUInt16(dt.Second);
Milliseconds = Convert.ToUInt16(dt.Millisecond);
}
public SYSTEMTIME(ushort year, ushort month, ushort day, ushort hour = 0, ushort minute = 0, ushort second = 0, ushort millisecond = 0)
{
Year = year;
Month = month;
Day = day;
Hour = hour;
Minute = minute;
Second = second;
Milliseconds = millisecond;
DayOfWeek = 0;
}
public static implicit operator DateTime(SYSTEMTIME st)
{
if (st.Year == 0 || st == MinValue)
return DateTime.MinValue;
if (st == MaxValue)
return DateTime.MaxValue;
return new DateTime(st.Year, st.Month, st.Day, st.Hour, st.Minute, st.Second, st.Milliseconds, DateTimeKind.Utc);
}
public static bool operator ==(SYSTEMTIME s1, SYSTEMTIME s2)
{
return (s1.Year == s2.Year && s1.Month == s2.Month && s1.Day == s2.Day && s1.Hour == s2.Hour && s1.Minute == s2.Minute && s1.Second == s2.Second && s1.Milliseconds == s2.Milliseconds);
}
public static bool operator !=(SYSTEMTIME s1, SYSTEMTIME s2)
{
return !(s1 == s2);
}
public static readonly SYSTEMTIME MinValue, MaxValue;
static SYSTEMTIME()
{
MinValue = new SYSTEMTIME(1601, 1, 1);
MaxValue = new SYSTEMTIME(30827, 12, 31, 23, 59, 59, 999);
}
public override bool Equals(object obj)
{
if (obj is SYSTEMTIME)
return ((SYSTEMTIME)obj) == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
}
/// <summary>
/// When a handle returned is no longer needed, it should be closed by calling RegCloseKey.
/// </summary>
private static UIntPtr ConnectToRegistryHive(string RemoteComputer, uint hKey)
{
UIntPtr computerRegHive = UIntPtr.Zero;
RegConnectRegistry(#"\\" + RemoteComputer, hKey, out computerRegHive);
return computerRegHive;
}
/// <summary>
/// When a handle returned is no longer needed, it should be closed by calling RegCloseKey.
/// </summary>
private static UIntPtr OpenRegistrySubKey(UIntPtr CurrentHKey, string SubKeyName, RegSAM desiredSAM)
{
UIntPtr hRegKey = UIntPtr.Zero;
RegOpenKeyEx(CurrentHKey, SubKeyName, 0, desiredSAM, out hRegKey);
return hRegKey;
}
private static DateTime GetRegistryKeyLastWriteTime(UIntPtr hKey)
{
FILETIME ft = new FILETIME();
int ret = RegQueryInfoKey(hKey, null, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, out ft);
if(ret == 0)
{
SYSTEMTIME st = new SYSTEMTIME(DateTime.MinValue);
FileTimeToSystemTime(ref ft, out st);
//Thanks to a highly developed SYSTEMTIME struct which has a DateTime implicit operator .... it's like magic!
DateTime LastWriteTime = st;
return LastWriteTime.ToLocalTime();
}
return DateTime.MinValue;
}
As for why the Win32_NetworkLoginProfile fails, the machine is pulling the datestamp on accounts from a Domain Controller, so it's complete inaccurate as to actual local logins on the machine.

RunProcessAsUser causing problems

I have an application that is being started by a Service automatically when the user logs on to his account. The application in question is a Winforms application and the problem is that sometimes when the application is started from the service it inexplicably hangs. Killing it and running it once more without a service works fine.
I am not sure why this is happening and why it only happens occasionally (not all the time). I always check the new process information and it is always running under the correct session of the logged in user.
I am not sure if I am doing something wrong when impersonating the user but in any case I am listing the code just so that maybe someone can find a flaw in it:
public int RunWithTokenInSession(IntPtr token, int nSessionID)
{
IntPtr primaryToken = GetUserTokenOfSessoin((uint)nSessionID);
if (primaryToken == IntPtr.Zero)
{
return -1;
}
STARTUPINFO StartupInfo = new STARTUPINFO();
processInfo_ = new PROCESS_INFORMATION();
StartupInfo.cb = Marshal.SizeOf(StartupInfo);
//StartupInfo.wShowWindow = (short)ShowCommands.SW_HIDE;
StartupInfo.lpDesktop = "Winsta0\\Default";
SECURITY_ATTRIBUTES Security1 = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES Security2 = new SECURITY_ATTRIBUTES();
string command = "\"" + processPath_ + "\"";
if ((arguments_ != null) && (arguments_.Length != 0))
{
command += " " + arguments_;
}
IntPtr lpEnvironment = IntPtr.Zero;
bool resultEnv = CreateEnvironmentBlock(out lpEnvironment, primaryToken, false);
if (resultEnv != true)
{
int nError = GetLastError();
}
bool b = CreateProcessAsUser(primaryToken, null, command, ref Security1, ref Security2, false, /*CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS |*/ CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS, lpEnvironment, null, ref StartupInfo, out processInfo_);
int error = 0;
if (!b)
{
error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
Debug.WriteLine(message);
}
DestroyEnvironmentBlock(lpEnvironment);
CloseHandle(primaryToken);
return error;
}
And this is the code for GetUserTokenOfSessoin:
public static IntPtr GetUserTokenOfSessoin(uint dwSessionId)
{
IntPtr currentToken = IntPtr.Zero;
IntPtr primaryToken = IntPtr.Zero;
IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
IntPtr hUserToken = IntPtr.Zero;
IntPtr hTokenDup = IntPtr.Zero;
bool bRet = WTSQueryUserToken(dwSessionId, out currentToken);
if (bRet == false)
{
int n = GetLastError();
return IntPtr.Zero;
}
bool fInAdminGroup = false;
//IntPtr hToken = IntPtr.Zero;
IntPtr hTokenToCheck = IntPtr.Zero;
IntPtr pElevationType = IntPtr.Zero;
IntPtr pLinkedToken = IntPtr.Zero;
int cbSize = 0;
if (Environment.OSVersion.Version.Major >= 6)
{
// Running Windows Vista or later (major version >= 6).
// Determine token type: limited, elevated, or default.
// Allocate a buffer for the elevation type information.
cbSize = sizeof(TOKEN_ELEVATION_TYPE);
pElevationType = Marshal.AllocHGlobal(cbSize);
if (pElevationType == IntPtr.Zero)
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
// Retrieve token elevation type information.
if (!GetTokenInformation(currentToken,
TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
// Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(pElevationType);
// If limited, get the linked elevated token for further check.
if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
{
// Allocate a buffer for the linked token.
cbSize = IntPtr.Size;
pLinkedToken = Marshal.AllocHGlobal(cbSize);
if (pLinkedToken == IntPtr.Zero)
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
// Get the linked token.
if (!GetTokenInformation(currentToken, TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken, cbSize, out cbSize))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
// Marshal the linked token value from native to .NET.
hTokenToCheck = Marshal.ReadIntPtr(pLinkedToken);
bRet = DuplicateTokenEx(hTokenToCheck, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
}
else
{
bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
}
}
else
{
// XP
bRet = DuplicateTokenEx(currentToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, IntPtr.Zero, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, TOKEN_TYPE.TokenPrimary, out primaryToken);
}
if (bRet == false)
{
int lastError = Marshal.GetLastWin32Error();
return IntPtr.Zero;
}
return primaryToken;
}
Now the issue seems to exclusively happen on Windows Server 2008 R2 as I haven't been able to reproduce it on any other version of Windows so I was wondering if there is anything special about Server 2008 and do I need to take extra security measures or obtain an extra privilege to run the process as the user.

GetPhysicalMonitorsFromHMONITOR returned handle is always null

On the Media Foundation SDK there is the GetPhysicalMonitorsFromHMONITOR function
that I am trying to implement using C# but with no luck ...
In the returned PHYSICAL_MONITOR[], the function returns the string description of the monitor but for some mysterious reasons, the hPhysicalMonitor handle remains at 0.
I have generated the signatures with P/Invoke Interop Assistant with minor modifications.
Does the PHYSICAL_MONITOR structure or anything else needs further tuning ?
Thank you.
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WindowsFormsApplication1;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public enum MC_DISPLAY_TECHNOLOGY_TYPE
{
MC_SHADOW_MASK_CATHODE_RAY_TUBE,
MC_APERTURE_GRILL_CATHODE_RAY_TUBE,
MC_THIN_FILM_TRANSISTOR,
MC_LIQUID_CRYSTAL_ON_SILICON,
MC_PLASMA,
MC_ORGANIC_LIGHT_EMITTING_DIODE,
MC_ELECTROLUMINESCENT,
MC_MICROELECTROMECHANICAL,
MC_FIELD_EMISSION_DEVICE,
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct PHYSICAL_MONITOR
{
public IntPtr hPhysicalMonitor;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] public string szPhysicalMonitorDescription;
}
#region Imports
[DllImport("user32.dll", EntryPoint = "MonitorFromWindow")]
public static extern IntPtr MonitorFromWindow(
[In] IntPtr hwnd, uint dwFlags);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorTechnologyType")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorTechnologyType(
IntPtr hMonitor, ref MC_DISPLAY_TECHNOLOGY_TYPE pdtyDisplayTechnologyType);
[DllImport("dxva2.dll", EntryPoint = "GetMonitorCapabilities")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMonitorCapabilities(
IntPtr hMonitor, ref uint pdwMonitorCapabilities, ref uint pdwSupportedColorTemperatures);
[DllImport("dxva2.dll", EntryPoint = "DestroyPhysicalMonitors")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DestroyPhysicalMonitors(
uint dwPhysicalMonitorArraySize, ref PHYSICAL_MONITOR[] pPhysicalMonitorArray);
[DllImport("dxva2.dll", EntryPoint = "GetNumberOfPhysicalMonitorsFromHMONITOR")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetNumberOfPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, ref uint pdwNumberOfPhysicalMonitors);
[DllImport("dxva2.dll", EntryPoint = "GetPhysicalMonitorsFromHMONITOR")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPhysicalMonitorsFromHMONITOR(
IntPtr hMonitor, uint dwPhysicalMonitorArraySize, [Out] PHYSICAL_MONITOR[] pPhysicalMonitorArray);
#endregion
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e)
{
// Get monitor handle.
uint dwFlags = 0u;
IntPtr ptr = MonitorFromWindow(Handle, dwFlags);
// Get number of physical monitors.
uint pdwNumberOfPhysicalMonitors = 0u;
bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);
if (b1)
{
// Get physical monitors.
uint dwPhysicalMonitorArraySize = 0u;
dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
//NOTE : Handles remain null !
bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);
if (pPhysicalMonitorArray[0].hPhysicalMonitor
== IntPtr.Zero)
{
throw new Exception("ERROR !");
}
// Monitor has capabilities to do that ?
if (b2)
{
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
bool b3 = GetMonitorCapabilities(
ptr, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
// If yes, get technology type.
if (b3)
{
MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
bool b4 = GetMonitorTechnologyType(ptr, ref type);
if (b4)
{
// Do work.
}
else
{
throw new Exception("Couldn't get monitor technology type.");
}
}
else
{
throw new Exception("Couldn't get monitor capabilities.");
}
}
else
{
throw new Exception("The monitor doesn't have the required capabilities.");
}
bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
if (!b5)
{
throw new Exception("Couldn't destroy physical monitors.");
}
}
else
{
throw new Exception("Couldn't get number of physical monitors.");
}
}
}
}
Your statement:
The function returns the string description of the monitor but for some mysterious reasons, the hMonitor handle remains at 0.
is correct. If you look at the docs here, you'll see that hMonitor is clearly an [in] parameter and will not be changed.
Update following comment:
Sorry, didn't realize you meant the physical handle being returned in the structure. All the information I can find on that particular problem seems to indicate that your monitor probably isn't fully DDC/CI compatible (e.g., here).
All your structure definitions look fine to me, based on the docs on MSDN for that particular call. And indeed, it is populating the description for you.
What is the value for the number of physical monitors being returned from GetNumberOfPhysicalMonitorsFromHMONITOR (pdwNumberOfPhysicalMonitors)?
Also, what is the size of your PHYSICAL_MONITOR structure and are you running in 32 or 64 bits?
It is alright that the hPhysicalMonitor value is 0. However, in the question's code sample all calls after the GetPhysicalMonitorsFromHMONITOR should use the hPhysicalMonitor reference instead of the ptr reference. The updated Form_Load method should be the following:
private void Form1_Load(object sender, EventArgs e)
{
// Get monitor handle.
uint dwFlags = 0u;
IntPtr ptr = MonitorFromWindow(Handle, dwFlags);
// Get number of physical monitors.
uint pdwNumberOfPhysicalMonitors = 0u;
bool b1 = GetNumberOfPhysicalMonitorsFromHMONITOR(ptr, ref pdwNumberOfPhysicalMonitors);
if (b1)
{
// Get physical monitors.
uint dwPhysicalMonitorArraySize = 0u;
dwPhysicalMonitorArraySize = pdwNumberOfPhysicalMonitors;
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
//NOTE : Handles remain null !
bool b2 = GetPhysicalMonitorsFromHMONITOR(ptr, dwPhysicalMonitorArraySize, pPhysicalMonitorArray);
// Monitor has capabilities to do that ?
if (b2)
{
uint pdwMonitorCapabilities = 0u;
uint pdwSupportedColorTemperatures = 0u;
bool b3 = GetMonitorCapabilities(pPhysicalMonitorArray[0].hPhysicalMonitor, ref pdwMonitorCapabilities, ref pdwSupportedColorTemperatures);
// If yes, get technology type.
if (b3)
{
MC_DISPLAY_TECHNOLOGY_TYPE type = MC_DISPLAY_TECHNOLOGY_TYPE.MC_SHADOW_MASK_CATHODE_RAY_TUBE;
bool b4 = GetMonitorTechnologyType(pPhysicalMonitorArray[0].hPhysicalMonitor, ref type);
if (b4)
{
// Do work.
}
else
{
throw new Exception("Couldn't get monitor technology type.");
}
}
else
{
throw new Exception("Couldn't get monitor capabilities.");
}
}
else
{
throw new Exception("The monitor doesn't have the required capabilities.");
}
bool b5 = DestroyPhysicalMonitors(dwPhysicalMonitorArraySize, ref pPhysicalMonitorArray);
if (!b5)
{
throw new Exception("Couldn't destroy physical monitors.");
}
}
else
{
throw new Exception("Couldn't get number of physical monitors.");
}
}
The monitor supports this function because with software like softMCCS and WinI2C/DDC,
the properties are returned correctly.
The return pdwNumberOfPhysicalMonitors value is 1 which is correct.
As you can see, its size is pdwNumberOfPhysicalMonitors :
PHYSICAL_MONITOR[] pPhysicalMonitorArray = new PHYSICAL_MONITOR[dwPhysicalMonitorArraySize];
And I am running Vista 32.
It is somewhat strange because half of it works, that's now about 4 days I am over it but still no progress ...
Thank you.

Resources