$theTitle=wp_title(" - ", false); if($theTitle != "") { ?>
About Virtualization, VDI, SBC, Application Compatibility and anything else I feel like
While browsing through my old projects folder I found a little commandline tool that I wrote about a year ago. I needed to detect a certain published application on a Citrix environment in the loginscript.
The tool detect the current Citrix published applicationname or if you are running Terminal Server aka Remote Desktop Services the Initial Program name and stores this in an environment variable (APPNAME).
There are no parameters and there are no special dependancies (such as MFCom).
CtxPubApp (2540 downloads)I have installed a new rating plugin that gives you, my readers, a convenient and fast method to give feedback. So please do so, let me know what posts you find interesting!
I have also added a Contact form in case you have any questions, article suggestions or maybe even consultation requests. The contact page is an attempt to streamline the e-mails I get from this blog so I hope this will work π
Today just some fun stuff with ASM, probably not the most recommended way to do things but for sure the most geeky way π
Get the Current Session Id:
1 2 3 4 5 6 | function GetCurrentSessionId: DWORD; asm mov eax,fs:[$00000018]; // Get TEB mov eax,[eax+$30]; // PPEB mov eax,[eax+$1d4]; // PEB.SessionId end; |
Get the Current Console Session Id:
1 2 3 4 | function GetConsoleSessionId: DWORD; asm mov eax, [$7ffe02d8]; end; |
And… if we can read it we can also write it?
1 2 3 4 5 6 | procedure SetCurrentSessionId(const SessionId: DWORD); asm mov edx,fs:[$00000018]; mov edx,[edx+$30]; mov [edx+$1d4], SessionId; end; |
and
1 2 3 4 5 6 7 8 9 10 | procedure SetConsoleSessionId(const SessionId: DWORD); var p: PDWORD; OldProtect: DWORD; begin p := PDWORD($7ffe02d8); Win32Check(VirtualProtect(p, SizeOf(p), PAGE_READWRITE, @OldProtect)); p^ := SessionId; Win32Check(VirtualProtect(p, SizeOf(p), OldProtect, @OldProtect)); end; |
You can safely try it since it of course affects the current process only, so don’t worry.
And perhaps more usefull
1 2 3 4 5 6 | procedure SetIsDebuggerPresent(const Value: Boolean); asm mov edx,fs:[$00000018]; // TEB mov edx, [edx+$30]; // PPEB mov byte ptr[edx+2], Value; // +0x002 BeingDebugged : UChar end; |
17 Jun // php the_time('Y') ?>
I needed to obtain the Fully Qualified Domain Name (FQDN) for a given NetBios domain name. Eg from MYDOMAIN to dc=mydomain,dc=local.
I did some tests with the TranslateName API and if you append a \ to the domain name it returns the FQDN.
Here is a short example:
If you look into the registry in the key HKLM\System\CurrentControlSet\ProductOptions you will find several licensing related Values.
The ProductType and ProductSuite keys contain the OS Suite and Edition, but the ProductPolicy key is much more interesting. So let’s have a closer look at it, open RegEdit and DoubleClick the key, you will something like the screenshot below, a Binary Value:
As you can see the license names are there as a Unicode string and later on I will show you how we can read the values. But because I didn’t want to extract all the names manually I decided to see if I could reverse the used structure because it didn’t look very complicated. Using a Hex Editor I could determine the important part of the structure.
9 Jun // php the_time('Y') ?>
Again a about post about using the Virtual TreeView component (did I mention it’s brilliant?), this time I will talk about memory leaks.
I often use Records to hold the treedata, and usually the record holds some string data (eg a caption) and an (a reference to) an Interface or Object(List) that holds more data.
If you are familiar with Virtual Tree then you know that you must can the NodeData in the OnFreeNode event.
When working with the Virtual TreeView component the most optimized way of adding (or removing child nodes is by changing the ChildCount.
I often make the mistake of change the ChildCount of a Node using:
1 | Node^.ChildCount := Count; |
If you look into the source you will see why this will not work, the proper way is:
1 | VirtualTree.ChildCount[Node] := Count; |
This is mainly a note to self since I tend to forget it all the time π
Previously I discussed IDirectoryObject, today I will show how to change a user’s password with IDirectoryObject.
I didn’t find any documentation except a kb article describing how to use pure ldap to do it. Of course I could have used IADsUser::SetPassword but I decided not to because of the following reasons:
All example code I found was .NET based using the .NET wrappers for Active Directory and seemed to be meant for use in Adam rather than full Active Directory (it set port number to 389 and password mode to cleartext).
In the end it’s not very difficult but nonetheless it took me a while before I got it right.
We can write to the unicodePwd attribute which wants the password as a double quoted unicode string. If you look at this attribute with AdsiEdit you’ll see that the type is Octet String and that it can be written only.
I was tricked with Delphi’s QuotedStr function for a while because it doesn’t return a double but single quoted string π
Below a small snippet from the upcoming JwsclActiveDirectory that shows how to use it: Read the rest of this entry »
A few days ago I wrote about Using Windows Dialogs in your own programs, wouldn’t it be nice to be able to use Windows Resource Strings for the same reasons?
Loading a resource string is not difficult, let’s look at some examples:
1 2 3 4 5 6 7 8 9 10 11 12 | function LoadResourceString(const DllName: String; ResourceId: Integer): String; var hDLL: THandle; Buffer: array[0..MAX_PATH] of Char; begin hDLL := LoadLibrary(PChar(DllName)); if hDLL = 0 then Exit; if LoadString(hDll, ResourceId, Buffer, Length(Buffer)) > 0 then Result := Buffer; end; |
This uses the LoadString api to load a Resource String from an Executable or Dll by it’s resource Id. An Example might call might be:
1 | LoadResourceString('dsadmin.dll', 226) |
This loads the string with ResourceId 226 from dsadmin.dll(.mui):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | STRINGTABLE LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US { 224, "Windows cannot complete the password change for %2 because:\n%1" 225, "Windows cannot access object %2 because:\n%1The object may have been deleted by another administrator in this enterprise." 226, "The New and Confirm passwords must match. Please re-type them." 228, "Object %2 has been disabled." 229, "Windows cannot disable object %2 because:\n%1" 231, "Object %2 has been enabled." 232, "Windows cannot enable object %2 because:\n%1" 233, "Create a new object..." 237, "Mo&ve...\nMoves the selected object" 238, "The password for %2 cannot be set due to insufficient privileges. Windows will attempt to disable this account. If this attempt fails, the account will become a security risk. Contact an administrator as soon as possible to repair this. Before this user can log on, the password should be set, and the account must be enabled." } |
As you can see in this example, some resource strings have identifiers such as %1 and %2 which are used in the FormatMessage Api. How can we use that from Delphi?
I wrote a very simple wrapper for it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | function FormatMsg(const Source: String; const Args: array of const): String; var i: Integer; ArgArray: array of Pointer; Buffer: PChar; begin for i := Low(Args) to High(Args) do begin SetLength(ArgArray, i+1); case Args[i].VType of vtExtended:; // not supported, should raise Exception else ArgArray[i] := Args[i].VPointer; end; end; if FormatMessage(FORMAT_MESSAGE_FROM_STRING or FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_ARGUMENT_ARRAY, PChar(Source), 0, 0, @Buffer, 0, @ArgArray[0]) > 0 then begin Result := Buffer; // replace \n (linefeed) with #13#10 Result := StringReplace(Result, '\n', #13#10, [rfReplaceAll]); LocalFree(DWORD(Buffer)); end else begin SetLength(Result, 0); end; end; |
And here is a usage example:
1 2 3 | Memo1.Lines.Add (FormatMsg( 'Windows cannot complete the password change for %2 because:\n%1', ['the password doesn''t meet complexity requirements', 'John Doe'])); |
The Result of this is:
Windows cannot complete the password change for John Doe because:
the password doesn’t meet complexity requirements
Today I reused a unit I wrote a long time ago for TSAdminEx that shows Resource Dialogs from DLL’s or Executables. I wrote it for a couple of reasons:
The code is hardly rocket science and could probably be improved and made more sophisticated but it works for me. I decided to share it since you may find it usefull.
Here is a small usage example that shows the Reset Password dialog from Active Directory Users & Computers. This dialog is in dsadmin.dll (on Windows Vista/7 you will find it in ds.admin.dll.mui in the language subfolder eg %systemroot%\system32\en-US but you can load it using just the dll name).
It looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 215 DIALOGEX 0, 0, 252, 139 STYLE DS_MODALFRAME | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_CONTEXTHELP CAPTION "Reset Password" LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US FONT 8, "MS Shell Dlg" { CONTROL "&New password:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 10, 79, 10 CONTROL "", 220, EDIT, ES_LEFT | ES_PASSWORD | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 92, 7, 153, 14 CONTROL "&Confirm password:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 28, 79, 10 CONTROL "", 222, EDIT, ES_LEFT | ES_PASSWORD | ES_AUTOHSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 92, 25, 153, 14 CONTROL "&User must change password at next logon", 261, BUTTON, BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 7, 46, 237, 10 CONTROL "The user must logoff and then logon again for the change to take effect.", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 14, 61, 231, 8 CONTROL "", 8327, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 7, 76, 238, 16 CONTROL "Unlock the user's &account", 8328, BUTTON, BS_AUTOCHECKBOX | BS_LEFT | BS_TOP | BS_MULTILINE | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 14, 96, 230, 10 CONTROL "OK", 1, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 140, 118, 50, 14 CONTROL "Cancel", 2, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 195, 118, 50, 14 } |