dotnet interop:
[quoted text, click to view] > //** Store the unmanaged string into a managed string **// > sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, >typeof(SERVICE_FAILURE_ACTIONS));
Where did unmanagedArray come from? Mattias -- Mattias Sjögren [C# MVP] mattias @ mvps.org http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Hi, I've got a problem storing a string into unmanaged memory, witch can't be restored to managed code. I've build a NT Service manager, witch acces the Service properties throug advapi32 calls. I'm pretty sure the string is stored correct into the unmanged code, because thru the default windows service manager I found the right value, only I want to get the string back myselft thru a call from c#. Thnx! some code parts: //** The struct for setting the service failure actions **// [StructLayout(LayoutKind.Sequential)] public struct SERVICE_FAILURE_ACTIONS { [MarshalAs(UnmanagedType.U4)] public int dwResetPeriod; public IntPtr lpRebootMsg; public IntPtr lpCommand; [MarshalAs(UnmanagedType.U4)] public int cActions; [MarshalAs(UnmanagedType.U4)] public int lpsaActions; } //** Setting the string to a unmanaged place**// IntPtr tmpMsg = IntPtr.Zero; tmpMsg = Marshal.StringToHGlobalAnsi("MY TEST STRING!!!"); // Set the SERVICE_FAILURE_ACTIONS struct SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS(); sfa.cActions = numActions; sfa.dwResetPeriod = this.failResetTime; sfa.lpCommand = tmpCmd; sfa.lpRebootMsg = tmpMsg; sfa.lpsaActions = tmpBuf.ToInt32(); // Call the ChangeServiceFailureActions() abstraction of ChangeServiceConfig2() rslt = ChangeServiceFailureActions(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); //** Store the unmanaged string into a managed string **// sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, typeof(SERVICE_FAILURE_ACTIONS)); // cAtions, lpsaActions are correct in the sfa object. string rebootMsg = Marshal.PtrToStringAnsi(sfa.lpRebootMsg); // this string (rebootMsg) is incorrect
Sorry, not all code paste on previous message. The code for getting the string from unmanaged code: bool fRet = false; uint dwBytesNeeded = 8192; SERVICE_FAILURE_ACTIONS sfa; IntPtr nullValue = new IntPtr(0); fRet = QueryServiceConfiguration(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, nullValue, 0, ref dwBytesNeeded); IntPtr unmanagedArray = Marshal.AllocHGlobal((int)dwBytesNeeded); fRet = QueryServiceConfiguration(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, unmanagedArray, dwBytesNeeded, ref dwBytesNeeded); sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, typeof(SERVICE_FAILURE_ACTIONS)); string reboot = Marshal.PtrToStringAnsi(sfa.lpRebootMsg); ///////////////// //The QueryServiceConfiguration method is: // Win32 function to Query on the service config config for the advanced service properties [DllImport("advapi32.dll", EntryPoint = "QueryServiceConfig2")] public static extern bool QueryServiceConfiguration( IntPtr hService, int dwInfoLevel, IntPtr lpInfo, uint size, ref uint bytesneeded); -- Sent via .NET Newsgroups
Bram, There appears to be a bug in QueryServiceConfig2A, the ANSI version of the API. Like most ANSI APIs it calls the Unicode (W) version internally and then converts the strings back to ANSI but in this case it does so incorrectly. The workaround is to call the Unicode version instead. Just add CharSet=CharSet.Auto (or CharSet.Unicode) to your DllImport attributes and use PtrToStringAuto or PtrToStringUnicode instead. Mattias -- Mattias Sjögren [C# MVP] mattias @ mvps.org http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
Mattias, Thnx again for your reply. Unfortunatly the string can't be stored as Unicode, because when i do that the 'lpCommand' LPTSTR from the SERVICE_FAILURE_ACTIONS, that i've set isn't stored correct (as i can see in the Service Recovery window, from Windows). Also adding the CharSet attribute to the Dllimport results in a incorrect string. As i store the string as Marshal.StringToHGlobalAnsi(this.failRunCommand); as told in my previous message, it is stored correctly (as i see in service properties), but the code below gets a string thru the 'QueryServiceConfig2' Apicall that's incorrect. What I'm I doing wrong? IntPtr scmHndl = IntPtr.Zero; IntPtr svcHndl = IntPtr.Zero; // Open the service control manager scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); // Open the service svcHndl = OpenService(scmHndl, "Actemium Service_x", SERVICE_ALL_ACCESS); // Get the configuration information. bool fRet = false; uint dwBytesNeeded = 8192; SERVICE_FAILURE_ACTIONS sfa; IntPtr nullValue = new IntPtr(0); fRet = QueryServiceConfiguration2(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, nullValue, 0, ref dwBytesNeeded); IntPtr unmanagedArray = Marshal.AllocHGlobal((int)dwBytesNeeded); fRet = QueryServiceConfiguration2(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, unmanagedArray, dwBytesNeeded, ref dwBytesNeeded); sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, typeof(SERVICE_FAILURE_ACTIONS)); string reboot = Marshal.PtrToStringAnsi(sfa.lpRebootMsg); //The svcHndl seems correct because the lpsaActions and the cActions are correct //Unfortunatly the sfa.lpRebootMsg IntPtr is incorrect and results in a half or uncorrect string
[quoted text, click to view] >Thnx again for your reply. Unfortunatly the string can't be stored as >Unicode, because when i do that the 'lpCommand' LPTSTR from the >SERVICE_FAILURE_ACTIONS, that i've set isn't stored correct (as i can >see in the Service Recovery window, from Windows). Also adding the >CharSet attribute to the Dllimport results in a incorrect string.
Can you post your Unicode-ified code together with the DllImports and struct? I think it should work if done right. [quoted text, click to view] >What I'm I doing wrong?
If you're still calling the ANSI version of QueryServiceConfig2 then it's not something you're doing wrong, it's the API bug. Mattias -- Mattias Sjögren [C# MVP] mattias @ mvps.org http://www.msjogren.net/dotnet/ | http://www.dotnetinterop.com
I've put the code together with dllimports and struct into a test project, hope you see what's wrong. Bram. [StructLayout(LayoutKind.Sequential)] public struct SERVICE_FAILURE_ACTIONS { [MarshalAs(UnmanagedType.U4)] public int dwResetPeriod; //[MarshalAs(UnmanagedType.LPTStr)] //public string lpRebootMsg; //[MarshalAs(UnmanagedType.LPTStr)] //public string lpCommand; [MarshalAs(UnmanagedType.U4)] public int lpRebootMsg; [MarshalAs(UnmanagedType.U4)] public int lpCommand; [MarshalAs(UnmanagedType.U4)] public int cActions; [MarshalAs(UnmanagedType.U4)] public int lpsaActions; } [DllImport("advapi32.dll")] public static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, int dwDesiredAccess); [DllImport("advapi32.dll")] public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, int dwDesiredAccess); [DllImport("advapi32.dll")] public static extern IntPtr LockServiceDatabase(IntPtr hSCManager); [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] public static extern bool ChangeServiceFailureActions(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_FAILURE_ACTIONS lpInfo); [DllImport("advapi32.dll", EntryPoint = "QueryServiceConfig2A", CharSet = CharSet.Ansi)] public static extern bool QueryServiceConfiguration(IntPtr hService, int dwInfoLevel, IntPtr lpInfo, uint size, ref uint bytesneeded); [DllImport("advapi32.dll")] public static extern bool CloseServiceHandle(IntPtr hSCObject); [DllImport("advapi32.dll")] public static extern bool UnlockServiceDatabase(IntPtr hSCManager); private const int SC_MANAGER_ALL_ACCESS = 0xF003F; private const int SERVICE_ALL_ACCESS = 0xF01FF; private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2; private const int SERVICE_NO_CHANGE = -1; private const int ERROR_ACCESS_DENIED = 5; public ArrayList FailureActions; private void SetFailureActions() { //Register the failure actions FailureActions.Clear(); FailureActions.Add(new FailureAction(RecoverAction.Restart, 60000)); FailureActions.Add(new FailureAction(RecoverAction.RunCommand, 2000)); FailureActions.Add(new FailureAction(RecoverAction.None, 3000)); IntPtr scmHndl = IntPtr.Zero; IntPtr svcHndl = IntPtr.Zero; IntPtr tmpBuf = IntPtr.Zero; IntPtr svcLock = IntPtr.Zero; IntPtr tmpMsg = IntPtr.Zero; IntPtr tmpCmd = IntPtr.Zero; try { scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); svcLock = LockServiceDatabase(scmHndl); svcHndl = OpenService(scmHndl, "MyServiceName", SERVICE_ALL_ACCESS); int numActions = FailureActions.Count; int[] actions = new int[numActions * 2]; int currInd = 0; foreach (FailureAction fa in FailureActions) { actions[currInd] = (int)fa.Type; actions[++currInd] = fa.Delay; currInd++; //If the FailureActions is reboot then Grand shutdown privilege } tmpBuf = Marshal.AllocHGlobal(numActions * 8); Marshal.Copy(actions, 0, tmpBuf, numActions * 2); tmpCmd = Marshal.StringToHGlobalAnsi("MyCommand.exe"); tmpMsg = Marshal.StringToHGlobalAnsi("Time to reboot!"); //tmpMsg = Marshal.StringToHGlobalUni("Time to reboot!"); SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS(); sfa.cActions = numActions; sfa.dwResetPeriod = SERVICE_NO_CHANGE; //sfa.lpCommand = "My Test Command"; //sfa.lpRebootMsg = "My Reboot Message"; sfa.lpCommand = tmpCmd.ToInt32(); sfa.lpRebootMsg = tmpMsg.ToInt32(); sfa.lpsaActions = tmpBuf.ToInt32(); bool rslt = ChangeServiceFailureActions(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); Marshal.FreeHGlobal(tmpBuf); tmpBuf = IntPtr.Zero; } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { if (scmHndl != IntPtr.Zero) { if (svcLock != IntPtr.Zero) { UnlockServiceDatabase(svcLock); svcLock = IntPtr.Zero; } CloseServiceHandle(scmHndl); scmHndl = IntPtr.Zero; } if (svcHndl != IntPtr.Zero) { CloseServiceHandle(svcHndl); svcHndl = IntPtr.Zero; } if (tmpBuf != IntPtr.Zero) { Marshal.FreeHGlobal(tmpBuf); tmpBuf = IntPtr.Zero; } } } private void GetFailureActions() { IntPtr scmHndl = IntPtr.Zero; IntPtr svcHndl = IntPtr.Zero; IntPtr tmpBuf = IntPtr.Zero; IntPtr nullValue = new IntPtr(0); try { scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); svcHndl = OpenService(scmHndl, "MyServiceName", SERVICE_ALL_ACCESS); uint dwBytesNeeded = 8192; SERVICE_FAILURE_ACTIONS sfa; bool fRet = QueryServiceConfiguration(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, nullValue, 0, ref dwBytesNeeded); IntPtr unmanagedArray = Marshal.AllocHGlobal((int)dwBytesNeeded); fRet = QueryServiceConfiguration(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, unmanagedArray, dwBytesNeeded, ref dwBytesNeeded); sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, typeof(SERVICE_FAILURE_ACTIONS)); //Why are the sfa.lpRebootMsg and lpCommand Pointers below, incorrect?? string reboot = Marshal.PtrToStringAnsi(new IntPtr(sfa.lpRebootMsg)); string command = Marshal.PtrToStringAnsi(new IntPtr(sfa.lpCommand)); //string command = Marshal.PtrToStringUni(new IntPtr(sfa.lpCommand)); Int32[] bins = new Int32[sfa.cActions * 2]; int offset = sfa.lpsaActions; for (int i = 0; i < sfa.cActions * 2; i++) { bins[i]=((Int32)Marshal.ReadIntPtr(new IntPtr(offset + i * 4))); } Marshal.Release(unmanagedArray); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public enum RecoverAction{ None=0, Restart=1, Reboot=2, RunCommand=3 } public class FailureAction { private RecoverAction type = RecoverAction.None; private int delay=0; public FailureAction(){} public FailureAction( RecoverAction actionType, int actionDelay ){ this.type = actionType; this.delay = actionDelay; } public RecoverAction Type{ get{ return type; } set{ type = value;} } public int Delay{ get{ return delay; } set{ delay = value;} } }
Anyone any idea why the string reboot and command, in my previous post aren't 'Time to reboot!' and 'MyCommand.exe' ? I'm still struggling with this code, and can't find any more resources. Do you know where to look for more information about the use of the 'QueryServiceConfig2A' Api call, or an example with the SERVICE_FAILURE_ACTIONS ? thanx, bram
[quoted text, click to view] "Bram Hoefnagel" <bhoefnagel@actemium.nl> wrote in message news:1133516542.598321.301180@z14g2000cwz.googlegroups.com... > I've put the code together with dllimports and struct into a test > project, hope you see what's wrong. > > Bram. > > [StructLayout(LayoutKind.Sequential)] > public struct SERVICE_FAILURE_ACTIONS > { > [MarshalAs(UnmanagedType.U4)] > public int dwResetPeriod; > //[MarshalAs(UnmanagedType.LPTStr)] > //public string lpRebootMsg; > //[MarshalAs(UnmanagedType.LPTStr)] > //public string lpCommand; > [MarshalAs(UnmanagedType.U4)] > public int lpRebootMsg; > [MarshalAs(UnmanagedType.U4)] > public int lpCommand; > [MarshalAs(UnmanagedType.U4)] > public int cActions; > [MarshalAs(UnmanagedType.U4)] > public int lpsaActions; > } > > [DllImport("advapi32.dll")] > public static extern IntPtr OpenSCManager(string lpMachineName, string > lpDatabaseName, int dwDesiredAccess); > > [DllImport("advapi32.dll")] > public static extern IntPtr OpenService(IntPtr hSCManager, string > lpServiceName, int dwDesiredAccess); > > [DllImport("advapi32.dll")] > public static extern IntPtr LockServiceDatabase(IntPtr hSCManager); > > [DllImport("advapi32.dll", EntryPoint = "ChangeServiceConfig2")] > public static extern bool ChangeServiceFailureActions(IntPtr hService, > int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref > SERVICE_FAILURE_ACTIONS lpInfo); > > [DllImport("advapi32.dll", EntryPoint = "QueryServiceConfig2A", CharSet > = CharSet.Ansi)] > public static extern bool QueryServiceConfiguration(IntPtr hService, > int dwInfoLevel, IntPtr lpInfo, uint size, ref uint bytesneeded); > > [DllImport("advapi32.dll")] > public static extern bool CloseServiceHandle(IntPtr hSCObject); > > [DllImport("advapi32.dll")] > public static extern bool UnlockServiceDatabase(IntPtr hSCManager); > > private const int SC_MANAGER_ALL_ACCESS = 0xF003F; > private const int SERVICE_ALL_ACCESS = 0xF01FF; > private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2; > private const int SERVICE_NO_CHANGE = -1; > private const int ERROR_ACCESS_DENIED = 5; > > public ArrayList FailureActions; > > private void SetFailureActions() > { //Register the failure actions > FailureActions.Clear(); > FailureActions.Add(new FailureAction(RecoverAction.Restart, > 60000)); > FailureActions.Add(new FailureAction(RecoverAction.RunCommand, > 2000)); > FailureActions.Add(new FailureAction(RecoverAction.None, 3000)); > > IntPtr scmHndl = IntPtr.Zero; > IntPtr svcHndl = IntPtr.Zero; > IntPtr tmpBuf = IntPtr.Zero; > IntPtr svcLock = IntPtr.Zero; > IntPtr tmpMsg = IntPtr.Zero; > IntPtr tmpCmd = IntPtr.Zero; > > try > { > scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); > svcLock = LockServiceDatabase(scmHndl); > svcHndl = OpenService(scmHndl, "MyServiceName", > SERVICE_ALL_ACCESS); > > int numActions = FailureActions.Count; > int[] actions = new int[numActions * 2]; > int currInd = 0; > foreach (FailureAction fa in FailureActions) > { > actions[currInd] = (int)fa.Type; > actions[++currInd] = fa.Delay; > currInd++; > //If the FailureActions is reboot then Grand shutdown > privilege > } > > tmpBuf = Marshal.AllocHGlobal(numActions * 8); > Marshal.Copy(actions, 0, tmpBuf, numActions * 2); > > tmpCmd = Marshal.StringToHGlobalAnsi("MyCommand.exe"); > tmpMsg = Marshal.StringToHGlobalAnsi("Time to reboot!"); > //tmpMsg = Marshal.StringToHGlobalUni("Time to reboot!"); > > SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS(); > > sfa.cActions = numActions; > sfa.dwResetPeriod = SERVICE_NO_CHANGE; > //sfa.lpCommand = "My Test Command"; > //sfa.lpRebootMsg = "My Reboot Message"; > sfa.lpCommand = tmpCmd.ToInt32(); > sfa.lpRebootMsg = tmpMsg.ToInt32(); > sfa.lpsaActions = tmpBuf.ToInt32(); > > bool rslt = ChangeServiceFailureActions(svcHndl, > SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa); > Marshal.FreeHGlobal(tmpBuf); tmpBuf = IntPtr.Zero; > } > catch (Exception ex) > { Console.WriteLine(ex.Message); } > finally > { > if (scmHndl != IntPtr.Zero) > { if (svcLock != IntPtr.Zero) > { UnlockServiceDatabase(svcLock); > svcLock = IntPtr.Zero; } > CloseServiceHandle(scmHndl); > scmHndl = IntPtr.Zero; } > if (svcHndl != IntPtr.Zero) > { CloseServiceHandle(svcHndl); > svcHndl = IntPtr.Zero; } > if (tmpBuf != IntPtr.Zero) > { Marshal.FreeHGlobal(tmpBuf); > tmpBuf = IntPtr.Zero; } > } > } > > private void GetFailureActions() > { > IntPtr scmHndl = IntPtr.Zero; > IntPtr svcHndl = IntPtr.Zero; > IntPtr tmpBuf = IntPtr.Zero; > IntPtr nullValue = new IntPtr(0); > > try > { > scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); > svcHndl = OpenService(scmHndl, "MyServiceName", > SERVICE_ALL_ACCESS); > > uint dwBytesNeeded = 8192; > SERVICE_FAILURE_ACTIONS sfa; > > bool fRet = QueryServiceConfiguration(svcHndl, > SERVICE_CONFIG_FAILURE_ACTIONS, nullValue, 0, ref dwBytesNeeded); > > IntPtr unmanagedArray = > Marshal.AllocHGlobal((int)dwBytesNeeded); > fRet = QueryServiceConfiguration(svcHndl, > SERVICE_CONFIG_FAILURE_ACTIONS, unmanagedArray, dwBytesNeeded, ref > dwBytesNeeded); > > sfa = > (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, > typeof(SERVICE_FAILURE_ACTIONS)); > > //Why are the sfa.lpRebootMsg and lpCommand Pointers below, > incorrect?? > string reboot = Marshal.PtrToStringAnsi(new > IntPtr(sfa.lpRebootMsg)); > string command = Marshal.PtrToStringAnsi(new > IntPtr(sfa.lpCommand)); > //string command = Marshal.PtrToStringUni(new > IntPtr(sfa.lpCommand)); > > Int32[] bins = new Int32[sfa.cActions * 2]; > int offset = sfa.lpsaActions; > > for (int i = 0; i < sfa.cActions * 2; i++) > { bins[i]=((Int32)Marshal.ReadIntPtr(new IntPtr(offset + i * > 4))); } > Marshal.Release(unmanagedArray); > } > catch (Exception ex) > { Console.WriteLine(ex.Message); } > } > > > public enum RecoverAction{ None=0, Restart=1, Reboot=2, RunCommand=3 } > > public class FailureAction > { > private RecoverAction type = RecoverAction.None; > private int delay=0; > public FailureAction(){} > public FailureAction( RecoverAction actionType, int actionDelay ){ > this.type = actionType; > this.delay = actionDelay; > } > > public RecoverAction Type{ get{ return type; } set{ type = value;} > } > public int Delay{ get{ return delay; } set{ delay = value;} }
Willy Denoyette [MVP] schreef: [quoted text, click to view] > Made a couple of changes, like UNICODE function calls and string members in > structure definition (services are NT only so don't use the ascii > functions). > Also I would sugest you to use a more .NET friendly solution for this, using > the System.Management classes and WMI you can do the same in a more portable > way. > > Anyway, following should work. > > Willy.
Thnx for your response Willy, unfortunatly your code results the same reboot and command strings as mine. mostly: "???\v" etc. bram
[quoted text, click to view] "Bram Hoefnagel" <bhoefnagel@actemium.nl> wrote in message news:1134731419.814383.138580@g43g2000cwa.googlegroups.com... > > Willy Denoyette [MVP] schreef: >> Made a couple of changes, like UNICODE function calls and string members >> in >> structure definition (services are NT only so don't use the ascii >> functions). >> Also I would sugest you to use a more .NET friendly solution for this, >> using >> the System.Management classes and WMI you can do the same in a more >> portable >> way. >> >> Anyway, following should work. >> >> Willy. > > Thnx for your response Willy, unfortunatly your code results the same > reboot and command strings as mine. mostly: "???\v" etc. > > bram >
This sample works for me. Did you try to build and run the code snip I posted? Willy.
[quoted text, click to view] Willy Denoyette [MVP] wrote: > This sample works for me. Did you try to build and run the code snip I > posted? > > Willy.
Yes i'v tried your console sample on 2 pc's running win2k. With my own service and the winmngr serive, all result in a string containing unknown characters. bram
[quoted text, click to view] "Bram Hoefnagel" <bhoefnagel@actemium.nl> wrote in message news:1134868427.603993.211910@f14g2000cwb.googlegroups.com... > > Willy Denoyette [MVP] wrote: >> This sample works for me. Did you try to build and run the code snip I >> posted? >> >> Willy. > > Yes i'v tried your console sample on 2 pc's running win2k. With my own > service and the winmngr serive, all result in a string containing > unknown characters. > bram >
Change the signatures of the functions such that the unicode version is used. [DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError = true)] public static extern bool QueryServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo, uint size, ref uint bytesneeded); or: [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError = true)] Willy.
I've changed it to Unicode (as Mattias Sj=F6gren suggested earlier), but still the same results. Also tried it on a win XP and 2003 virtual PC. I'm close to give up query the Service Failure Actions...
Yeah! that's it! The CharSet of the struct must be set. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct SERVICE_FAILURE_ACTIONS Thnx for helping me finding a solution! -- Sent via .NET Newsgroups
[quoted text, click to view] "Bram Hoefnagel" <bhoefnagel@actemium.nl> wrote in message news:1134989533.809149.305220@g43g2000cwa.googlegroups.com...
I've changed it to Unicode (as Mattias Sjögren suggested earlier), but still the same results. Also tried it on a win XP and 2003 virtual PC. I'm close to give up query the Service Failure Actions... Well, I don't get it, it works for me on XP and W2K3. This is the output of the program[1], after I added "RebootWinmgmt" and "CommandWinmgmt" to the winmgmt service using: sc qfailure reboot= RebootWinmgmt sc qfailure command= CommandWinmgmt output of [1] Reset Period: 86400 Reboot: RebootWinmgmt Command: CommandWinmgmt Actions: 2 1 60000 1 60000 [1] using System; using System.Runtime.InteropServices; using System.Collections; using System.Text; namespace Willys { [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)] public struct SERVICE_FAILURE_ACTIONS { public int dwResetPeriod; [MarshalAs(UnmanagedType.LPWStr)] public string lpRebootMsg; [MarshalAs(UnmanagedType.LPWStr)] public string lpCommand; public int cActions; public IntPtr lpsaActions; } class Tester { [DllImport("advapi32.dll")] public static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, int dwDesiredAccess); [DllImport("advapi32.dll")] public static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, int dwDesiredAccess); [DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError = true)] public static extern bool QueryServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo, uint size, ref uint bytesneeded); private const int SC_MANAGER_ALL_ACCESS = 0xF003F; private const int SERVICE_ALL_ACCESS = 0xF01FF; private const int SERVICE_CONFIG_FAILURE_ACTIONS = 0x2; private const int SERVICE_NO_CHANGE = -1; private const int ERROR_ACCESS_DENIED = 5; static void Main() { GetFailureActions(); } static void GetFailureActions() { IntPtr scmHndl = IntPtr.Zero; IntPtr svcHndl = IntPtr.Zero; IntPtr tmpBuf = IntPtr.Zero; IntPtr nullValue = new IntPtr(0); IntPtr unmanagedArray = IntPtr.Zero; try { scmHndl = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS); svcHndl = OpenService(scmHndl, "winmgmt", SERVICE_ALL_ACCESS); uint dwBytesNeeded = 0; SERVICE_FAILURE_ACTIONS sfa; bool fRet = QueryServiceConfig2(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, nullValue, 0, ref dwBytesNeeded); unmanagedArray = Marshal.AllocHGlobal((int)dwBytesNeeded); fRet = QueryServiceConfig2(svcHndl, SERVICE_CONFIG_FAILURE_ACTIONS, unmanagedArray, dwBytesNeeded, ref dwBytesNeeded); sfa = (SERVICE_FAILURE_ACTIONS)Marshal.PtrToStructure(unmanagedArray, typeof(SERVICE_FAILURE_ACTIONS)); Console.WriteLine("Reset Period: {0}",sfa.dwResetPeriod); string reboot = sfa.lpRebootMsg; string command = sfa.lpCommand; if(reboot != null) Console.WriteLine("Reboot: {0}",reboot); if(command != null) Console.WriteLine("Command: {0}",command); Console.WriteLine("Actions: {0}",sfa.cActions); int SIZE_OF_SC_ACTION = 2; // hardcode struct size in DWORD size Int32[] bins = new Int32[sfa.cActions * SIZE_OF_SC_ACTION]; IntPtr offset = sfa.lpsaActions; for (int i = 0; i < sfa.cActions * SIZE_OF_SC_ACTION; i++) { bins[i]=Marshal.ReadInt32(offset, i * sizeof(int)); } foreach(int c in bins) { Console.WriteLine(c); } Marshal.Release(unmanagedArray); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } } Willy.
[quoted text, click to view] "Bram Hoefnagel" <bhoefnagel@actemium.nl> wrote in message news:%23ivpGKLBGHA.2036@TK2MSFTNGP14.phx.gbl... > Yeah! that's it! > The CharSet of the struct must be set. > > [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] > public struct SERVICE_FAILURE_ACTIONS > > Thnx for helping me finding a solution! > > -- > Sent via .NET Newsgroups > http://www.dotnetnewsgroups.com Sorry if I didn't explicitly stated this. If you are using a Unicode version of a function, you should also use the unicode version of it's arguments. Anyway, the code should also work with the Ansi version, but here is the problem (as you noticed). The ansi version returns a string that is partly correct, the first part however is not correctly filled (that's why you noticed the unprintable chars), this looks like a bug in the ansi version of the function (I filed a bug). Note that these functions are only available on NT like OS, so there should be no reason to use the ansi versions whatsoever. Willy.
Don't see what you're looking for? Try a search.
|