There are not that many changes in this release as I was only updating it for my own use really but I figured other people may benefit from the new API definitions and managed methods included.
For anyone that doesn’t know what Cjwdev.WindowsApi is – it is a .NET DLL I have written that contains definitions for several native Windows APIs (80 to be precise) that enables you to do things you cannot do in the .NET framework already. As well as the raw API signatures, it also includes managed .NET methods that wrap a lot of these APIs up into methods that are easy to use from .NET code. So you can easily use these methods even if you have absolutely no experience calling Windows API functions from .NET. For more information and examples of what is included in the library see the various posts here: https://cjwdev.wordpress.com/category/cjwdev-windowsapi/
Anyway, here is a list of what is included in this latest release:
- The following API definitions were added to the ApiDefinitions class: WTSGetActiveConsoleSessionId, WTSQueryUserToken, CreateProcessAsUser, DestroyEnvironmentBlock, CreateEnvironmentBlock, AllocConsole, FreeConsole, AddFontResource, RemoveFontResource
- InstallFontForCurrentSession – Installs a font for the current session only (does not require admin permissions)
- RemoveFontForCurrentSession – Removes a font from the system font table for the current session only (does not require admin permissions)
- Overloaded versions of RenewIpAddresses and ReleaseIpAddresses that let you choose to ignore errors (so that if one NIC cannot be renewed/released for some reason then it will continue to attempt the operation on other NICs)
and here is the download link (make sure you extract the XML file to the same location as the DLL so that you get intellisense information for each method):
http://www.cjwdev.co.uk/DeveloperComponents/Cjwdev-WindowsAPI/Cjwdev.WindowsApi.zip
Hi, it´s seems very interesting your Component.
I would like to know, if it’s possible, how-to install a true type font in runtime, without admin privileges.
Thanks in advanced.
Are you asking how it actually works or asking for an example of how to use it to do that?
Hi, thanks for your fast answer.
At first I was looking for an example, but i lost a little time searching for the option InstallFontForCurrentSession and found it at NativeOperatingsystem.
Apparently is what I’m looking for:
– I have a program made in Visual Basic 2008 Express Edition and is working at work without having admin privileges;
– I’m trying to use true type fonts in my program, that are not installed on pcs at work;
– With your component i believe that it’s possible to install those fonts at startup, and then become useful to my program;
– I’m trying right now, that’s why i don’t have a final answer.
Thanks for your help!
Sorry my English (not my first language!)
Hi, can’t answer yet!
I’m facing a new problem: can’t use some fonts in visual basic at design time because it gives me a error: “Only True Type Fonts are supported”.
I’m trying to set the font Label1 with a font that i like, but it gives me that error. The same for other three true type fonts. Strange.
I’ll let you know later…
Hi again, sorry for take your time.
Some font that I’m trying to use are not supported bu visual basic 2008 express edition. So don’t need to install them with your component. Thanks anyway!
Hi,
Is it possible to open a treeview slowly from top to bottom in vs 2010 wpf ??
Thanks
I tested CreateProcessAsUser function with windows service and this works fine.
Except I cant use arguments. It there a way to use CreateProcessAsUser with arguments??
Thanks
Yeah just specify your arguments after the application path, the MSDN documentation doesn’t do a great job of explaining it but just do it so that the literal string you end up passing in to the lpCommandLine argument is “C:\Process.exe” “argument one” “argument 2” etc etc
http://msdn.microsoft.com/en-gb/library/windows/desktop/ms682429(v=vs.85).aspx
Yup read that MSDN and I have lost count trying to get this right:
WindowsApi.CreateProcessAsUser(UserTokenHandle, “”, “””C:\WINDOWS\system32\cmd.exe”” “”/C echo test”””, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
Is there a mistake here?
This is how I would do it:
WindowsApi.CreateProcessAsUser(UserTokenHandle, Nothing, """C:\WINDOWS\system32\cmd.exe"" ""/C"" ""echo"" ""test""", IntPtr.Zero, IntPtr.Zero, False, CREATE_UNICODE_ENVIRONMENT Or CREATE_NEW_CONSOLE, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
Although I would also recommend using the CreateEnvironmentBlock API to create the user’s environmental variables and passing that in to the 3rd to last parameter instead of Nothing. Some programs won’t work properly if the user’s environment isn’t setup correctly.
Still no lock =(
I cant get CREATE_UNICODE_ENVIRONMENT Or CREATE_NEW_CONSOLE declared
FYI, I’m developing new programmer….so here my full code
without argument work fine….hope this helps. Thanks
——————————————————-
Module Module1
Dim WindowsApi As New WindowsApi
Function run_as(ByVal apps_path As String, ByVal arg As String) As Boolean
Try
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
Dim StartInfo As New WindowsApi.STARTUPINFOW
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
If arg = “” Then
WindowsApi.CreateProcessAsUser(UserTokenHandle, apps_path, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
Else
WindowsApi.CreateProcessAsUser(UserTokenHandle, Nothing, arg, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
End If
If Not UserTokenHandle = IntPtr.Zero Then
WindowsApi.CloseHandle(UserTokenHandle)
End If
Return True
Catch ex As Exception
Return False
End Try
End Function
Sub Main()
‘run_as(“C:\WINDOWS\system32\cmd.exe”, “”)
run_as(“”, “””C:\WINDOWS\system32\cmd.exe”” “”/C”” “”echo”” “”wakaka”””)
Console.ReadLine()
End Sub
End Module
After leaving my computer for couple of hours and play with my 9 months baby boy, watching tv and do other things… I finally get this right. I found my problem after I write error to log file…should do this first than retrying blindly….
And I use this page .NET Windows API Library (Cjwdev.WindowsApi) … Hope this help someone like me =)
Function run_as(ByVal fpath As String, ByVal farg As String) As Boolean
Dim UserTokenHandle As IntPtr = IntPtr.Zero
Dim EnvironmentBlock As IntPtr = IntPtr.Zero
Dim ProcInfo As New ApiDefinitions.PROCESS_INFORMATION
Dim args() As String
args = farg.Split(" ")
Dim drvname As String = ""
Dim cmdline As String = """" & fpath & """"
For Each arg In args
cmdline = cmdline & " """ & arg & """"
Next
Try
Dim ConsoleSessionId As UInteger = ApiDefinitions.WTSGetActiveConsoleSessionId
F.file_write("C:\", "run_as.log", "Console session ID = " & ConsoleSessionId, 1)
F.file_write("C:\", "run_as.log", "Attempting to get handle to primary access token of console session user...", 1)
Dim QueryTokenResult As Boolean = ApiDefinitions.WTSQueryUserToken(ConsoleSessionId, UserTokenHandle)
If QueryTokenResult AndAlso Not UserTokenHandle = IntPtr.Zero Then
F.file_write("C:\", "run_as.log", "Attempting to get handle to primary access token of console session user...", 1)
Else
F.file_write("C:\", "run_as.log", "Failed to get handle to primary token, the last error reported was: " & New ComponentModel.Win32Exception().Message, 1)
Exit Function
End If
F.file_write("C:\", "run_as.log", "Creating environmental variable block for user...", 1)
Dim CreateEnvironmentResult As Boolean = ApiDefinitions.CreateEnvironmentBlock(EnvironmentBlock, UserTokenHandle, False)
If CreateEnvironmentResult AndAlso Not EnvironmentBlock = IntPtr.Zero Then
F.file_write("C:\", "run_as.log", "Successfully created environmental variable block", 1)
Else
F.file_write("C:\", "run_as.log", "Failed to create environmental variable block for user, the last error reported was: " & New ComponentModel.Win32Exception().Message, 1)
Exit Function
End If
Dim StartInfo As New ApiDefinitions.STARTUPINFO
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
F.file_write("C:\", "run_as.log", "Attempting to launch process...", 1)
Dim CreateProcessResult As Boolean = ApiDefinitions.CreateProcessAsUser(UserTokenHandle, Nothing, cmdline, IntPtr.Zero, IntPtr.Zero, False, ApiDefinitions.CREATE_UNICODE_ENVIRONMENT Or ApiDefinitions.CREATE_NEW_CONSOLE, EnvironmentBlock, "C:\WINDOWS\system32\", StartInfo, ProcInfo)
If CreateProcessResult AndAlso Not ProcInfo.dwProcessId = 0 Then
F.file_write("C:\", "run_as.log", "Process successfully launched in console session (Process ID = " & ProcInfo.dwProcessId & ")", 1)
Else
F.file_write("C:\", "run_as.log", "Failed to launch process, the last error reported was: " & New ComponentModel.Win32Exception().Message, 3)
End If
Finally
'Clean up, close handles
If Not UserTokenHandle = IntPtr.Zero Then
ApiDefinitions.CloseHandle(UserTokenHandle)
End If
If Not ProcInfo.hProcess = IntPtr.Zero Then
ApiDefinitions.CloseHandle(ProcInfo.hProcess)
End If
If Not ProcInfo.hThread = IntPtr.Zero Then
ApiDefinitions.CloseHandle(ProcInfo.hThread)
End If
If Not EnvironmentBlock = IntPtr.Zero Then
ApiDefinitions.DestroyEnvironmentBlock(EnvironmentBlock)
End If
End Try
Dim WaitForExit As Boolean = True
'Wait for the process to exit if that has been requested
If WaitForExit AndAlso Not ProcInfo.dwProcessId = 0 Then
Dim LaunchedProcess As Process = Nothing
Try
LaunchedProcess = Process.GetProcessById(CInt(ProcInfo.dwProcessId))
Catch ex As ArgumentException
F.file_write("C:\", "run_as.log", "Process has terminated: " & ex.ToString, 1)
End Try
If Not LaunchedProcess Is Nothing Then
F.file_write("C:\", "run_as.log", "Waiting for process to exit...", 1)
LaunchedProcess.WaitForExit()
F.file_write("C:\", "run_as.log", "Process has terminated", 1)
End If
End If
End Function
But I have another problem… something like this works
run_as(“C:\WINDOWS\system32\notepad.exe”, “C:\test.txt”)
It will open a C:\test.txt in notepad
But if I try this:
run_as(“C:\run_script.bat”, “regedit”)
This is sample of C:\run_script.bat
echo off
cls
set ty=%1
if "%ty%" == "runcmd" cmd
if "%ty%" == "compmgmtmsc" compmgmt.msc
if "%ty%" == "appwizcpl" appwiz.cpl
if "%ty%" == "ncpacpl" ncpa.cpl
if "%ty%" == "regedit" start regedit
I can see command prompt window is open and immediately close.
It only work if I change into this
if "%ty%" == "regedit" start C:\Windows\System32\regedt32.exe
Any idea what when wrong?
Chris, i modified your code from StartInConsoleSession.exe
Hope you dont mind. I tried StartInConsoleSession.exe but always get this error:
C:\StartInConsoleSession.exe C:\Windows\System32\cmd.exe
StartInConsoleSession.exe
Version 1.0.0.0
Developed by Chris Wright (cwright@cjwdev.co.uk)
Command line = “C:\Windows\System32\cmd.exe”
Wait for exit = False
Attempting to get console session ID…
Console session ID = 1
Attempting to get handle to primary access token of console session user…
Failed to get handle to primary token, the last error reported was: A required privilege is not held by the client
Yeah you can only run that code if you’re running as Local System (I did explain that in the blog post where I provided the link to StartInConsoleSession)
Creating shares does not seem to work with x64. Any ideas?
Unfortunately not, I never could get it working from a 64 bit process. I keep meaning to revisit it and figure it out but haven’t had chance. It will work fine on a 64 bit OS if you just make your process 32 bit though (e.g change the CPU type to x86 rather than AnyCPU or x64)
thanks