PageRenderTime 36ms CodeModel.GetById 4ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 1ms

/2.0/Samples/RegEditPHP/RegEditPHP/frmMain.user.php

#
PHP | 1215 lines | 919 code | 6 blank | 290 comment | 95 complexity | 918e03ea50ee3086e3fc623174759e5b MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1<? //Š Đonny 2009 - Part of Phalanger project
  2    import namespace RegEditPHP;
  3    import namespace System:::Windows:::Forms;
  4    import namespace Microsoft:::Win32;
  5    import namespace System;
  6    
  7    namespace RegEditPHP{
  8        ///<summary>Main application form</summary>
  9	    partial class frmMain extends System:::Windows:::Forms:::Form{
 10	        //This class represents main form of this application. It contains the most of the code.
 11//Initialization
 12             ///<summary>This name is used as name and text of placeholder child key</summary>
 13             const dummy = "dummy node"; //Each tree node in TreeView that have never been expanded is filled with one dummy node to have the + sign in front of itself (to appear expandable). This node is replaced with actual nodes before expanding.
 14             ///<summary>Gives access to localized resources</summary>
 15             private $Resources;//See ResourceAccessor.php
 16             ///<summary>Internal initialization method</summary>
 17             private function Init(){
 18                //Call to this method wa manually added to __construct() in frmMain.php
 19                //Following commented lines are no longer needed because pictures now can be added form designer
 20                //$this->tmiNew->Image = Program::$Resources->new;
 21                //$this->tmiNewKey->Image = Program::$Resources->folder->ToBitmap();
 22                //$this->tmiNewDWord->Image = 
 23                //$this->tmiNewQWord->Image = Program::$Resources->numeric->ToBitmap();
 24                //$this->tmiNewString->Image = 
 25                //$this->tmiNewExpandable->Image = 
 26                //$this->tmiNewMulti->Image = Program::$Resources->string->ToBitmap();
 27                //$this->tmiNewBinary->Image = Program::$Resources->binary->ToBitmap();
 28                //$this->tmiRename->Image = Program::$Resources->rename;
 29                //$this->tmiEdit->Image = Program::$Resources->edit;
 30                //$this->tmiDelete->Image = Program::$Resources->delete;
 31                //$this->tmiRefreshNode->Image = Program::$Resources->refresh;
 32                //Initialize sorter to sort list of values
 33                $this->Sorter = new Sorter($this->lvwRegistry);
 34                //Fill nodes added in designer with placeholder subnodes
 35                //This can be done in designer as well but it's so much clicking and use of self::dummy is better than use of "dummy key" (which'd be case of designer)
 36                foreach($this->tvwRegistry->Nodes as $node):
 37                    $node->Nodes->Add(self::dummy)->Name=self::dummy;
 38                endforeach;
 39             }
 40//Main menu  
 41             //Handles click to Exit menu item
 42             private function tmiExit_Click(System:::Object $sender, System:::EventArgs $e) {
 43                $this->Close();//Close the main form (it terminates the application)
 44             }
 45            //Handles click to Language menu item
 46            private function tmiLanguage_Click(System:::Object $sender, System:::EventArgs $e) {
 47                //Create instance of form for language sleection
 48                $lSel = new LanguageSelector();
 49                //Show it and test if user clicked OK
 50                if($lSel->ShowDialog($this) == DialogResult::OK):
 51                    //If so, the application must be restarted (changing UI strings without restart is too much work)
 52                    //To restart the application we need know path of it - location of assembly
 53                    //So get the assembly from type contained in it
 54                    $MyType = CLRTypeOf frmMain;
 55                    $MyPath = $MyType->Assembly->Location;
 56                    try{ //Launch it
 57                        System:::Diagnostics:::Process::Start($MyPath);
 58                    }catch(System:::Exception $ex){ //This probably will not happen
 59                        self::OnError(Program::$Resources->e_Restart."\r\n$ex->Message");
 60                        return;
 61                    }
 62                    //If application successfully started, this can be closed
 63                    $this->Close();
 64                endif;
 65            }
 66            //Handles click on the Jump menu item
 67            private function tmiJump_Click(System:::Object $sender, System:::EventArgs $e) {
 68                //get path to jump to using InputBox (see InputBox.user.php)
 69                $Path = InputBox::GetInput(Program::$Resources->JumpToKey,Program::$Resources->JumpToKey_t);
 70                if(!is_null($Path)) //InputBox::GetInput returns null on cancel
 71                    $this->JumpToKey($Path);//Do the jump
 72            }
 73            //Handles click on the Refresh all menu item
 74            private function tmiRefreshAll_Click(System:::Object $sender, System:::EventArgs $e) {
 75                //Remember currently selected key
 76                $OldPath = $this->tvwRegistry->SelectedNode->FullPath;
 77                //Clear content of all top-level nodes
 78                foreach($this->tvwRegistry->Nodes as $node):
 79                    $node->Nodes->Clear;
 80                    //And add placeholder into each of them to appear expandable
 81                    $node->Nodes->Add(self::dummy)->Name=self::dummy;
 82                endforeach; 
 83                //For user convenience, navigate to node that was selected when reloading (I hate when reloading changes my status)
 84                $this->JumpToKey($OldPath);    
 85            }
 86            ///<summary>Navigates to key with given path</summary>
 87            ///<param name="Path">Path full to navigate too</param>
 88            ///<returns type="bool">success</returns>
 89            private function JumpToKey(string $Path){
 90                //Firts trim trailing backslashes
 91                //We must use $Path->ToString() because we want to work with .NET string and .NET string is not same as PHP string (i think this is bug, teher should be only one string)
 92                while($Path->ToString()->EndsWith("\\"))
 93                    $Path = $Path->ToString()->Substring(0,strlen($Path) - 1);
 94                //You can use many of PHP built-in function you are familiar with. Sometimes they are nicer/better tna .NET ones - as explode()
 95                $PathParts = explode("\\",$Path);
 96                $CurrentNodes = $this->tvwRegistry->Nodes;//Starting with top-level nodes
 97                foreach($PathParts as $Part)://For each path part
 98                    foreach($CurrentNodes as $Node)://Wee look for node with same at current level
 99                        if($Node->Name->ToLower() == $Part->ToString()->ToLower())://Note: Usage of ToString() on PHP string is required to use ToLower(); $Node->Name is not PHP string but .NET string
100                            $this->NoExpandQuestion=true;//Turn of expand question ofr HKCR
101                            $Node->Expand();//Expand node
102                            $this->NoExpandQuestion=false;//Turn the question back on
103                            $CurrentNodes = $Node->Nodes;//Dive one more level
104                            $LastNode = $Node;//Remember last succesfully found node (in case of failure, we will navigate to last-match level)
105                            continue 2;//Next (deeper) level
106                        endif;
107                    endforeach;
108                    self::OnError(Program::$Resources->e_KeyDoesNotExist($Path));//continue 2 above skips this line if node is found
109                    break;
110                endforeach;
111                if(!is_null($LastNode))://If there was matc at least at one level
112                    $this->tvwRegistry->SelectedNode = $LastNode;//select it
113                    $LastNode->EnsureVisible();//And scroll it to view
114                    return $LastNode->FullPath->ToLower() == $Path->ToString()->ToLower();//Only when all levels succeeded we consider jump successfull
115                else:
116                    return false;//The root name was unknown
117                endif;
118            }
119            //Hanndles click on the Jump to same key under ... menu item
120            //It navigates to node with same addres but sapped first part HKLM<->HKCU (if possible)
121            private function tmiJumpToSame_Click(System:::Object $sender, System:::EventArgs $e) {
122                if($this->tvwRegistry->SelectedNode->FullPath->StartsWith("HKEY_CURRENT_USER\\")):
123                    $start=HKEY_CURRENT_USER;//current 1st part
124                    $new=HKEY_LOCAL_MACHINE;//new 1st part
125                else:
126                    $new=HKEY_CURRENT_USER;//new 1st part
127                    $start=HKEY_LOCAL_MACHINE;//current 1st part
128                endif;
129                $new= $new . $this->tvwRegistry->SelectedNode->FullPath->Substring(strlen($start));///replace 1st part
130                $this->JumpToKey($new);//Navigate to new path (if navigation is not possible, navigates as near as can)
131            }
132            //Handles dropdown opening of the Tools top-level menu item
133            private function tmiTools_DropDownOpening(System:::Object $sender, System:::EventArgs $e) {
134                //We enable/disable Jump to same menu item depending on if user is under HKCU or HKLM or not
135                $this->tmiJumpToSame->Enabled = (
136                    $this->tvwRegistry->SelectedNode->FullPath->StartsWith("HKEY_CURRENT_USER\\") or
137                    $this->tvwRegistry->SelectedNode->FullPath->StartsWith("HKEY_LOCAL_MACHINE\\"));
138                //And adjust text to show name of target hive (top-level node)
139                if($this->tmiJumpToSame->Enabled and $this->tvwRegistry->SelectedNode->FullPath->StartsWith("HKEY_CURRENT_USER\\")):
140                    $this->tmiJumpToSame->Text = Program::$Resources->JumToSameKey("HKLM");
141                elseif($this->tmiJumpToSame->Enabled):
142                    $this->tmiJumpToSame->Text = Program::$Resources->JumToSameKey("HKCU");
143                endif;
144            }
145            //Handles click on About menu item
146            private function tmiAbout_Click(System:::Object $sender, System:::EventArgs $e) {
147                $ad=new dlgAbout();//Create about dialog
148                $ad->ShowDialog($this);//And show it
149            }
150
151             
152//Tree
153             ///<summary>If false, user is askt if (s)he really wants to expand HKCR</summary>
154             private $NoExpandQuestion = false;
155             //Called before tree node is expanded
156             //Dummy sub keys are deleted in this event and actual node content is loaded
157             private function tvwRegistry_BeforeExpand(System:::Object $sender, System:::Windows:::Forms:::TreeViewCancelEventArgs $e) {
158                if(!$this->NoExpandQuestion and $e->Node->FullPath==HKEY_CLASSES_ROOT and $e->Node->Nodes->Count == 1):
159                    //PHPBUG:
160                    //We use Sorter::Iterate because indexing and default properties does not work well in current version of Phalanger
161                    if(Sorter::Iterate($e->Node->Nodes->GetEnumerator(),0)->Name == self::dummy):
162                        //If node is HKCR and it was never expanded before, ask user if (s)he really wants to expand it (because it typically contains as many 2nd-level subkey as loading take a while (even in MS's regedit)
163                        if(MessageBox::Show(Program::$Resources->ExpandHKCR,Program::$Resources->ExpandHKCR_t,MessageBoxButtons::YesNo,MessageBoxIcon::Information) != DialogResult::Yes):
164                            //Cancels expanding (node will remain unexpanded)
165                            $e->Cancel = true;
166                            return;
167                        endif;
168                    endif;
169                endif;
170                //Test if node hals only one child - the Dummy
171                if($e->Node->Nodes->Count==1):
172                    //Following 2 lines are same as Sorter::Iterate($e->Node->Nodes->GetEnumerator(),0) (legacy)
173                    $nem=$e->Node->Nodes->GetEnumerator();
174                    $nem->MoveNext();
175                    if($nem->Current->Name=self::dummy):
176                        //Need load childs from registry
177                        $this->Cursor = Cursors::$WaitCursor;//Set cursor to horglass (it may take a while)
178                        try{
179                            self::FillNode($e->Node);//Load subkeys
180                        }catch(System:::Exception $ex){
181                            $e->Node->Nodes->Clear();//When there is error, treat key as empty
182                            self::OnError($ex->Message);//Show error message
183                        }
184                        $this->Cursor = Cursors::$Default;//Revert cursor icon
185                    endif;
186                endif;    
187             }
188             //Caled after tree node is expanded   
189             private function tvwRegistry_AfterExpand(System:::Object $sender, System:::Windows:::Forms:::TreeViewEventArgs $e) {
190                //We handle change of icon here
191                //Note: Tree node has 2 icons - normal and selected
192                // Both icons are taken from associated image list (set in designer)
193                // and we want them to be the same, thus same key
194                $e->Node->ImageKey="open";
195                $e->Node->SelectedImageKey="open";
196             }
197            //Called after tree node is collapsed
198             private function tvwRegistry_AfterCollapse(System:::Object $sender, System:::Windows:::Forms:::TreeViewEventArgs $e) {
199                //Same as above, but change icon to closed
200                $e->Node->ImageKey="closed";
201                $e->Node->SelectedImageKey="closed";
202             }
203             ///<summary>Fills node with subnodes representing corresponding key subkeys</summary>
204             ///<param name="Node">Node to fill</param>
205             ///<returns type="void"/>
206             private static function FillNode(TreeNode $Node){
207                //1st clear any current content
208                //It's typically dummy node, but for refresh it may be anything
209                $Node->Nodes->Clear();
210                //Get key for node path
211                //Nice with TreeViewIs that it gives path of node which is immediatelly usable for registry lookup
212                $Key=self::getRegistryKey($Node->FullPath);     
213                $SubKeys=$Key->GetSubKeyNames();//Enumerate sub keys (this may throw an exception and it must be handles by caller)
214                foreach($SubKeys as $SubKeyName)://Add the keys to current node
215                    $SubKey = $Node->Nodes->Add($SubKeyName);//Add it (this creates node with given text, adds it and returns it)
216                    $SubKey->Name = $SubKeyName;//Set its name (it is used by Fullpath)
217                    $SubKey->ImageKey = "closed";//Set its image
218                    $SubKey->SelectedImageKey = "closed";
219                    $SubKey->Nodes->Add(self::dummy)->Name=self::dummy;//And fill it with dummy child (to seem to be axpandable)
220                endforeach;
221                //Note: Every node seems to be expandable if it has been never expanded
222                // so user may experience following:
223                // (S)he clicks the + and instead of node expanding, the + vanishes
224                // it's not 100% good behavior, but is quite common and saves us some pre-testing
225             }
226             ///<summary>Gets registry key for its path</summary>
227             ///<param name="Path">Full path of key to open</param>
228             ///<param name="writeable">True to open key for writing, false to open it as readonly</param>
229             ///<returns type="registryKey">Opened key</param>
230             private static function getRegistryKey(string $Path,bool $writeable = false){
231                //We must firts parse the path
232                $parts=explode("\\",$Path);//Explode it by \
233                //The bad thisng with .NET registry API is that there is no general-purpose function for opening registry key
234                // The top-level keys (so-called hives) must be treated separatelly
235                switch($parts[0])://So switch for them
236                    case HKCR://Shortcut names are not currently utilized by this program
237                    case HKEY_CLASSES_ROOT: $root=Registry::$ClassesRoot;
238                    break;
239                    case HKCU:
240                    case HKEY_CURRENT_USER: $root=Registry::$CurrentUser;
241                    break;
242                    case HKLM:
243                    case HKEY_LOCAL_MACHINE: $root=Registry::$LocalMachine;
244                    break;
245                    case HKU:
246                    case HKEY_USERS: $root=Registry::$Users;
247                    break;
248                    case HKCC:
249                    case HKEY_CURRENT_CONFIG: $root=Registry::$CurrentConfig;
250                    break;
251                    case HKDD:
252                    case HKEY_DYN_DATA: $root=Registry::$DynData;
253                    break;
254                    case HKPD:
255                    case HKEY_PERFORMANCE_DATA: $root=Registry::$PerformanceData;
256                    break;
257                    default: throw new CLRException(new ArgumentException(Program::$Resources->e_UnknownRoot));
258                endswitch;
259                if(count($parts)==1) return $root;//Return root for single-part path
260                //Otherwise open root's sub key (now ve have general-purpose function to open multiplůe levels at once)
261                return $root->OpenSubKey(i'String'::Join("\\",$parts,1,count($parts)-1),$writeable);
262                //Note: Two uncommon things at line above:
263                //1) i'String' is Phalanger way how to point to class or function that has same name as Phalanger keyword (in this case string). We use this i-preceded string in single quotes. i'String' means System:::String
264                //2) I pass $parts (PHP array) where .NET String[] array is expected
265                //PHPBUG:
266                //   It is strange, but Phalanger currently has not silent implicit conversion from string to System::String but has conversion of array to String[]
267             } 
268            //Called after node in tree is selected
269            private function tvwRegistry_AfterSelect(System:::Object $sender, System:::Windows:::Forms:::TreeViewEventArgs $e) {
270                //We need show values in this key
271                try{ //get key and show values for it
272                    $this->LoadValues(self::GetRegistryKey($e->Node->FullPath));
273                }catch(System:::Exception $ex){
274                    self::OnError($ex->Message);     
275                }
276                $this->tslKey->Text=$e->Node->FullPath;
277            }
278            
279            ///<summary>Loads values for given key rto ListView>/summary>
280            ///<param name="key">Key to load values from</param>
281            ///<returns type="void"/>
282            private function LoadValues(RegistryKey $key){
283                //Gate value names (may cause Exception, must be caught by caller)
284                $ValueNames=$key->GetValueNames();
285                //Clear list
286                $this->lvwRegistry->Items->Clear();
287                foreach($ValueNames as $Name)://For each name
288                    $item=$this->lvwRegistry->Items->Add($Name);//Create and add item
289                    $item->Name=$Name;//Set its name
290                    switch($key->GetValueKind($Name))://We must support regtlue types separately
291                        case RegistryValueKind::Binary://Binary (got as array of bytes)
292                            $item->ImageKey="binary";
293                            $kind=REG_BINARY;//You know - undefined constant's
294                            $value=$key->GetValue($Name);
295                            if(!is_null($value))$value=self::GetBytesString($value,&$alt);//Call helper method to display byte array
296                        break;    
297                        case RegistryValueKind::DWord://DWord (got as int32)
298                            $item->ImageKey="numeric";
299                            $kind=REG_DWORD;
300                            $value=$key->GetValue($Name);
301                            $alt="0x".$value->ToString("X");//Hexa
302                            $value=$value->ToString();//Decadic                
303                        break;    
304                        case RegistryValueKind::ExpandString://Expandable string (%something% is replaced by value of system variable something)
305                            $item->ImageKey="string";
306                            $kind=REG_EXPAND_SZ;
307                            $value=$key->GetValue($Name,null,RegistryValueOptions::DoNotExpandEnvironmentNames);//Unexpanded value
308                            $alt=$key->GetValue($Name);//Expanded value
309                        break;
310                        case RegistryValueKind::MultiString://MultistringgotasString
311                            $item->ImageKey="string";
312                            $kind=REG_MULTI_SZ;
313                            $value=$key->GetValue($Name);
314                            $value=System:::String::Join("; ",$value);//Just join it using semicolon
315                            $alt=$value;//No alternative sight
316                        break;
317                        case RegistryValueKind::QWord://QWord (got as int64) XP regedit does not support it, but we DO!
318                            $item->ImageKey="numeric";
319                            $kind=REG_QWORD;
320                            $value=$key->GetValue($Name);
321                            $alt="0x".$value->ToString("X");//Hexa
322                            $value=$value->ToString();//decadic
323                        break;
324                        case RegistryValueKind::i'String'://Normal string
325                            //PHPBUG:
326                            //This is littele inconsistent behavior:
327                            // While RegistryValueKind::String is invalid
328                            // System:::String is valid
329                            $item->ImageKey="string";
330                            $kind=REG_SZ;
331                            $value=$key->GetValue($Name);
332                            $alt=$value;//There is no alternative sight of plain text
333                        break;
334                        default://Unknown kind (tehre are more kinds of registry values - uncommon and I dunno what good for)
335                            //Just show that there is sth
336                            $item->ImageKey="unknown";
337                            $kind="unknown";    
338                            $value=Program::$Resources->UnknownValue;
339                            $alt=Program::$Resources->UnknownValueAlt;
340                    endswitch;
341                    //Fill subitems (2nd, 3rd, 4th columns in list view)
342                    $item->SubItems->Add($kind);
343                    $item->SubItems->Add($value);
344                    $item->SubItems->Add($alt);
345                endforeach;
346                $this->lvwRegistry->Sort();//Sort list (sorting is actually provided by Sorter.php)
347                $this->AfterSort();//Some after-sort settings
348            }  
349            ///<summary>Gets display string for byte array</summary>
350            ///<param name="bytes">Byte array to get values from</param>
351            ///<param name="alt" type=´"string">Output parameter filled with alternative (decimal) representation of <paramref name="bytes"/></param>
352            ///<returns type="string">String representation of byte array (2-digits hexadecimal numbers separated by spaces)</returns>
353            private static function GetBytesString(i'Array' $bytes,&$alt){
354                //Note: i'Array' means that we acceps System:::array, not PHP array
355                //Output parameters passed by reference are possible in PHP as well, but not commonly used. This uis the rare case when it is useful
356                // In phalanger you can use [out] attribute, whoch I'm not using here
357                //StringBuolder is efficient way of concatenating strings in .NET
358                $ret=new System:::Text:::StringBuilder(count($bytes)*3);//Initial capacity count*3 is not compulsory but is god for efficiency
359                $ret2=new System:::Text:::StringBuilder(count($bytes)*3);//For decimal capacity as approximate
360                foreach($bytes as $byte):
361                    if($ret->Length>0) $ret->Append(" ");//Add space, if non empty
362                    if($ret2->Length>0) $ret2->Append(" ");
363                    $ret->Append($byte->ToString("X2"));//Hexadecimal, 2 didigts    
364                    $ret2->Append($byte->ToString());//Decimal
365                endforeach;
366                $alt=$ret2->ToString(); //StringBuilder must be converted to string explicitly
367                return $ret->ToString(); 
368            }             
369            //Handles click on list view collumn
370            private function lvwRegistry_ColumnClick(System:::Object $sender, System:::Windows:::Forms:::ColumnClickEventArgs $e) {
371                //We do sorting here
372                if($this->Sorter->Column == $e->Column):
373                    //If user click same column 2nd or more times
374                    switch($this->Sorter->Order)://reverse order
375                        case SortOrder::Ascending:
376                            $this->Sorter->Order=SortOrder::Descending;
377                        break;
378                        default:$this->Sorter->Order=SortOrder::Ascending;
379                    endswitch;
380                else://CHange sort column and set order to ASC
381                    $this->Sorter->Order=SortOrder::Ascending;
382                    $this->Sorter->Column = $e->Column;
383                endif;
384                $this->lvwRegistry->Sort();//Force apply sorting
385                $this->AfterSort();//After sort operations
386            }            
387            ///<summary>Does common after ListView sort operations</summary>
388            ///<returns type="void"/>
389            private function AfterSort(){
390                foreach($this->lvwRegistry->Columns as $col)
391                    $col->ImageKey=null;//Remove sort image from all columns
392                //And set it for the used one using direction-aware image
393                Sorter::Iterate($this->lvwRegistry->Columns->GetEnumerator(),$this->Sorter->Column)->ImageKey = $this->Sorter->Order == SortOrder::Ascending ? 'asc' : 'desc';
394            }
395//Context menu and actions
396            //Called befor context menu is opened
397            private function cmsContext_Opening(System:::Object $sender, System:::ComponentModel:::CancelEventArgs $e) {
398                //Note: ContextMenuStrip is associated with TreeView and ListView in designer
399                //We hide/show and enable/disable certain menu items here based on conditions
400                //Note: The === compares 2 instances for bering reference equal (the same instance). It's stronger than ==.Phalanger behavior with CLR classes is a little different form original PHP usage.
401                if($this->cmsContext->SourceControl === $this->tvwRegistry and is_null($this->tvwRegistry->SelectedNode)):
402                    //No TreeNode selected - this should not happedn
403                    $e->Cancel=true;//Do not show the menu
404                    return;
405                endif;
406                //Edit only for values
407                $this->tmiEdit->Visible = (
408                    $this->cmsContext->SourceControl === $this->lvwRegistry and
409                    $this->lvwRegistry->SelectedItems->Count == 1);
410                //No rename for no value selected or more values selected
411                $this->tmiRename->Visible =
412                    !($this->cmsContext->SourceControl === $this->lvwRegistry and $this->lvwRegistry->SelectedItems->Count <> 1);
413                //No delete for no values selected
414                $this->tmiDelete->Visible = 
415                    !($this->cmsContext->SourceControl === $this->lvwRegistry and $this->lvwRegistry->SelectedItems->Count == 0);
416                //No delete for root
417                $this->tmiDelete->Enabled = 
418                    !($this->cmsContext->SourceControl === $this->tvwRegistry and is_null($this->tvwRegistry->SelectedNode->Parent));
419                //Select all only for values
420                $this->tmiSelectAll->Visible = $this->cmsContext->SourceControl === $this->lvwRegistry;
421                //If there is nothig to select ...
422                $this->tmiSelectAll->Enabled = $this->lvwRegistry->Items->Count > 0;
423                //Refres only for nodes
424                $this->tmiRefreshNode->Visible = $this->cmsContext->SourceControl === $this->tvwRegistry;
425                //Copy only for single key or current values
426                //Note: LIst veiw recognizec selected values and focused vakues
427                $this->tmiCopyFullPath->Enabled = (
428                    $this->cmsContext->SourceControl === $this->tvwRegistry or
429                    ($this->cmsContext->SourceControl === $this->lvwRegistry and !is_null($this->lvwRegistry->FocusedItem)));
430            }
431            //Handles attempt to rename tree node
432            private function tvwRegistry_BeforeLabelEdit(System:::Object $sender, System:::Windows:::Forms:::NodeLabelEditEventArgs $e) {
433                //Top-level cannot be renamed
434                $e->CancelEdit = $e->CancelEdit || is_null($e->Node->Parent);
435            }
436            //Hanldes confirmed rename of tree node
437            private function tvwRegistry_AfterLabelEdit(System:::Object $sender, System:::Windows:::Forms:::NodeLabelEditEventArgs $e) {
438                //Reaname can be cancled or it is not rename at all (user haven't changed text - indinated by null Label)
439                if(is_null($e->Label) or $e->Label == $e->Node->Text) $e->CancelEdit=true;//No change
440                if($e->CancelEdit) return;
441                $e->CancelEdit = !$this->RenameKey($e->Node, $e->Label);//Try to rename
442            }
443            //Handles confirned rename of values
444            private function lvwRegistry_AfterLabelEdit(System:::Object $sender, System:::Windows:::Forms:::LabelEditEventArgs $e) {
445                //Same as rename of key - the event can indicate no rename at all (null Label)
446                if(is_null($e->Label)) $e->CancelEdit = true;
447                $node = Sorter::Iterate($this->lvwRegistry->Items->GetEnumerator(),$e->Item);
448                if($node->Text == $e->Label) $e->CancelEdit = true;//No change
449                if($e->CancelEdit) return;
450                $e->CancelEdit = $this->RenameValue($node, $e->Label);//Try to rename
451            }
452            //Handles click on New key context menu item
453            private function tmiNewKey_Click(System:::Object $sender, System:::EventArgs $e) {
454                $this->AddKey();//Add the key
455            }
456            //Handles click on Rename context menu item
457            private function tmiRename_Click(System:::Object $sender, System:::EventArgs $e) {
458                //We just detect which control context menu is show on and let the control to deal with rename on its own (in fact 2 functions above)
459                if($this->cmsContext->SourceControl === $this->tvwRegistry):
460                    $this->tvwRegistry->SelectedNode->BeginEdit();//Tree
461                else:
462                   Sorter::Iterate($this->lvwRegistry->SelectedItems,0)->BeginEdit();//List
463                endif;
464            }
465            //Handles click on Edit context menu item
466            private function tmiEdit_Click(System:::Object $sender, System:::EventArgs $e) {
467                $this->EditValue();//Do the edit
468            }
469            //Handles doble-click on list view item
470            //Note: Some lama-users like to instruct system to activate list view item on single click instead of on double click (link behavior)
471            // If your ListView follows this user decision can be set in designer
472            private function lvwRegistry_ItemActivate(System:::Object $sender, System:::EventArgs $e) {
473                $this->EditValue();//Edit value value
474            }
475            //Handles click on delete on context menu item 
476            private function tmiDelete_Click(System:::Object $sender, System:::EventArgs $e) {
477                //We just detect control contet menu is shown on and call appropriate method
478                if($this->cmsContext->SourceControl === $this->tvwRegistry):
479                    $this->DeleteKey();//Delete key
480                else:
481                    $this->DeleteValues();//Delete value
482                endif;
483            }
484            //Handles key down when tree view is active
485            private function tvwRegistry_KeyDown(System:::Object $sender, System:::Windows:::Forms:::KeyEventArgs $e) {
486                //We are intrested only in some keys
487                //KeyData contains or combination of KeyCode and Ctrl+Alt+Shift state
488                switch($e->KeyData):
489                    case Keys::Delete: $this->DeleteKey();//Delete key (w/o any Ctrl+Shift+Alt)
490                    break;
491                    case Keys::F2://F2 key (w/o ...)
492                        if(!is_null($this->tvwRegistry->SelectedNode) and !is_null($this->tvwRegistry->SelectedNode->Parent)):
493                            $this->tvwRegistry->SelectedNode->BeginEdit();        
494                        endif;
495                    break;  
496                    case Keys::F7: $this->AddKey();//F7 - I love Total Commander :-)
497                endswitch;
498            }
499            //Handles key down on list view
500            private function lvwRegistry_KeyDown(System:::Object $sender, System:::Windows:::Forms:::KeyEventArgs $e) {
501                //Same note as abowe but we're interested in more keys
502                switch($e->KeyData):
503                    case Keys::Delete: $this->DeleteValues();//delete
504                    break;
505                    case Keys::F2://rename
506                        if(!is_null($this->lvwRegistry->FocusedItem))
507                            $this->lvwRegistry->FocusedItem->BeginEdit();
508                    break;
509                    case Keys::Control | Keys::A://This is how to uttilize the key combination
510                        foreach($this->lvwRegistry->Items as $item)//Select all items
511                            $item->Selected=true;
512                    break;
513                    case Keys::F4://Edit (like in TC)
514                    case Keys::Enter: $this->EditValue();//Edit
515                    break;
516                    case Keys::Shift | Keys::F4://New string (like in TC)
517                        $this->Addvalue(RegistryValueKind::i'String');
518                    break;
519                endswitch;
520            }
521            //Handles click on any of New value menu items
522            //Note: More events can have sam handler and more hahndlers can be attached to single event in .NET
523            private function tmiNewValue_Click(System:::Object $sender, System:::EventArgs $e) {
524                //Detect kind from item being clicked
525                if($sender === $this->tmiNewBinary)
526                    $kind = RegistryValueKind::Binary;
527                elseif($sender === $this->tmiNewDWord)
528                    $kind = RegistryValueKind::DWord;
529                elseif($sender === $this->tmiNewExpandable)
530                    $kind = RegistryValueKind::ExpandString;    
531                elseif($sender === $this->tmiNewMulti)
532                    $kind = RegistryValueKind::MultiString;
533                elseif($sender === $this->tmiNewQWord)
534                    $kind = RegistryValueKind::QWord;
535                elseif($sender === $this->tmiNewString)
536                    $kind = RegistryValueKind::i'String';
537                $this->Addvalue($kind);//Do add
538            }
539            ///<summary>deletes currently selected registry key</summary>
540            ///<returns type="bool">success</returns>
541            private function DeleteKey(){
542                $KeyName=$this->tvwRegistry->SelectedNode->Text;
543                //Ask user
544                if(MessageBox::Show(Program::$Resources->DeleteKey($KeyName),Program::$Resources->DeleteKey_t,MessageBoxButtons::YesNo,MessageBoxIcon::Question) == DialogResult::Yes):
545                    //We must open parent key and ask it to delete its child
546                    $parts=explode("\\",$this->tvwRegistry->SelectedNode->FullPath);
547                    $ParentPath=i'String'::Join("\\",$parts,0,count($parts)-1);//Parent path
548                    try{
549                        $ParentKey=$this->getRegistryKey($ParentPath,true);//Open parent
550                    }catch(System:::Exception $ex){
551                        self::OnError($ex->Message);
552                        return false;
553                    }
554                    try{
555                        $ParentKey->DeleteSubKeyTree($parts[count($parts)-1]);//Delete child
556                    }catch(System:::Exception $ex){
557                        self::OnError($ex->Message);
558                        return false;
559                    }
560                    $this->tvwRegistry->SelectedNode->Remove();//On success delete the node visualy as vell
561                    return true;
562                else:
563                    return false;
564                endif;
565            }
566            ///<summary>Deletes selected values</param>
567            ///<returns type="bool">success</returns>
568            private function DeleteValues(){
569                //First chose message
570                if($this->lvwRegistry->SelectedItems->Count == 1):
571                    //For one-value deletion as with value name
572                    $item1=Sorter::Iterate($this->lvwRegistry->SelectedItems->GetEnumerator(),0)->Text;
573                    $message= Program::$Resources->DeleteValue($item1);
574                else://Otherwise simly ask on values
575                    $message=Program::$Resources->DeleteValues;
576                endif;
577                //Ask user
578                if(MessageBox::Show($message,Program::$Resources->DeleteValues_t,MessageBoxButtons::YesNo,MessageBoxIcon::Question)==DialogResult::Yes):
579                    try{//Open key
580                        $key=$this->getRegistryKey($this->tvwRegistry->SelectedNode->FullPath,true);
581                    }catch(System:::Exception $ex){
582                        self::OnError($ex->Message);
583                        return false;
584                    }
585                    //Index of st selected item (to preselect something after deletion, users like it)
586                    $fsi=Sorter::Iterate($this->lvwRegistry->SelectedIndices->GetEnumerator(),0);
587                    //Number of items to delete (to detect skip)
588                    $todelcnt=$this->lvwRegistry->SelectedItems->Count;
589                    foreach($this->lvwRegistry->SelectedItems as $item):
590                        //Label is target for goto statement (Phalanger PHP extension)
591DeleteValue:            try{
592                            $key->DeleteValue($item->Name);//Try to delete
593                        }catch(System:::Exception $ex){//On error ask user what to do
594                            switch(self::OnError(Program::$Resources->e_DeleteValue($item->Name)."\r\n$ex->Message",MessageBoxButtons::AbortRetryIgnore)):
595                                case DialogResult::Ignore: continue 2;//Ignore, just procede to next selected value
596                                case DialogResult::Retry: goto DeleteValue;//Retry (this is where goto is usefully).
597                                default: break 2;//Stop deleteing more values (exit foreach loop)
598                            endswitch;
599                        }
600                        $deleted[]=$item;//Remeber deleted items (to delete them visually as well)
601                    endforeach;
602                    foreach($deleted as $deleteditem)//Delete items visually
603                        $this->lvwRegistry->Items->Remove($deleteditem);
604                    //If all selected items was deleted
605                    // there is no selected item now
606                    // if there is somethign to select    
607                    if(count($deleted) == $todelcnt and $this->lvwRegistry->Items->Count > 0):
608                        //We will select item near the deleted one
609                        $newIndex = max(min($this->lvwRegistry->Items->Count-1,$fsi-1),0);
610                        Sorter::Iterate($this->lvwRegistry->Items->GetEnumerator(),$newIndex)->Selected = true;    
611                    endif;
612                    return count($deleted) > 0;//It may indicate success or semi-success
613                else:
614                    return false;
615                endif;                
616            }
617            ///<summary>Adds key under curent key</summary>
618            ///<param name="parent">Node (not key) to add key into</param>
619            ///<param name="newname">Name of key to add. If empty user is asked.</param>
620            ///<param name="norefresh">True to not add the key to TreeView and return it instead</param>
621            ///<returns>Bool success; created key on success when norefresh was true</returns>
622            private function AddKey($parent=null, string $newname="",  bool $norefresh=false){
623                //This is somewhat complicated because it ca operate in ineractive and non-interactive mode
624                if(is_null($parent)):
625                    //Get parent node if we haven't got it
626                    if(is_null($this->tvwRegistry->SelectedNode)) return false;
627                    $parent = $this->tvwRegistry->SelectedNode;
628                endif; 
629                $Name=$newname;
630                if($newname<>"") goto testBS;//Do not ask for name
631                //Ask for name
632EnterName:      if(!is_null($Name=InputBox::GetInput(Program::$Resources->NameOfNewKey,Program::$Resources->CreateKey_t,$Name))):
633testBS:             if($Name->Contains("\\"))://Name cannot contain \
634                        self::OnError(Program::$Resources->e_InvalidName($Name));
635                        if($newname=="")
636                            goto EnterName;//Interactive mode (repeat enter)
637                        else return false;
638                    endif;
639                    try{ //Open paren registry key for writing
640                        $parentkey=$this->getRegistryKey($parent->FullPath,true);
641                    }catch(System:::Exception $ex){
642                        $this->OnError($ex->Message);
643                        return false;
644                    }
645                    //Check if key to be created already exists
646                    try{
647                        $existing = $parentkey->OpenSubKey($Name,false);
648                    }catch(System:::Exception $ex){
649                        $this->OnError($ex->Message);
650                        return false;
651                    }
652                    if(!is_null($existing)):
653                        self::OnError(Program::$Resources->e_KeyExists($Name));
654                        return false;
655                    endif;
656                    try{//Create it
657                       $newKey = $parentkey->CreateSubKey($Name);
658                    }catch(System:::Exception $ex){
659                        $this->OnError($ex->Message);
660                        return false;
661                    }
662                    if($norefresh) return $newKey;//Not interactive, return created key to caller
663                    //Otherwise navigate to the new key
664                    $wasdummy = 
665                        ($parent->Nodes->Count == 1 and Sorter::Iterate($parent->Nodes->GetEnumerator(),0)->Name=self::dummy);
666                    $parent->Expand();//Expand prent
667                    if($wasdummy)://If parent was not loaded, it is now loaded and contain newly created key
668                        foreach($parent->Nodes as $node)://search for it
669                            if($node->Name == $Name):
670                                $newNode=$node;//found
671                                break;
672                            endif;
673                        endforeach;
674                    else://Otherwise add it visually
675                        $newNode = $parent->Nodes->Add($Name);
676                        $newNode->Name =  $Name;
677                        $newNode->ImageKey = "closed";
678                        $newNode->SelectedImageKey = "closed";
679                    endif;
680                    if (!is_null($newNode)):
681                        $this->tvwRegistry->SelectedNode = $newNode;//Select new key
682                        $newNode->EnsureVisible();//and scrollit to view
683                    endif;
684                    return true;
685                else:
686                    return false;
687                endif;
688            }
689            ///<summary>Adds value of given type</summary>
690            ///<param name="type">Type of value to add</param>
691            ///<returns type="bool">success</returns>
692            private function Addvalue(int $type){
693                //PHPBUG:
694                //Note: We cannot declare $type as RegistryValueKind because it then will not assept values like RegistryValueKind::Binary (being it treated as int)
695                $editor = new ValueEditor();//Create value editor
696                $editor->SetValue(null,$type);//Initialize it
697                $editor->NameReadOnly=false;//Allow enter of name
698                if($editor->ShowDialog($this)==DialogResult::OK)://Show it
699                    try{
700                        //Open registry key to add value into
701                        $key=$this->getRegistryKey($this->tvwRegistry->SelectedNode->FullPath,true);
702                        try{//Check if value with same name exists
703                            $key->GetValueKind($editor->ValueName);
704                            self::OnError(Program::$Resources->e_ValueExists($editor->ValueName));
705                            return false;
706                        }catch(System:::IO:::IOException $ex){}//Non existent value is indicated by System:::IO:::IOExcpetion - and its what we want
707                        $key->SetValue($editor->ValueName,$editor->Value,$type);//Create it (create and change value are same operations)
708                    }catch(System:::Exception $ex){
709                        self::OnError($ex->Message);
710                        return false;
711                    }
712                    $this->LoadValues($key);//refresh list of values
713                    foreach($this->lvwRegistry->Items as $item)://Search for newly added
714                        if($item->Name==$editor->ValueName):
715                            $item->Selected=true;//select it
716                            $item->EnsureVisible();//and scroll it into view
717                            break;
718                        endif;
719                    endforeach; 
720                    return true;
721                else:
722                    return false;
723                endif;
724            }
725            ///<summary>Attempts to rename registry key</summary>
726            ///<param name="node">Tree node representing the key to reanem</param>
727            ///<param name="newname>New name of key</param>
728            ///<returns type="bool">success</returns>
729            private function RenameKey(TreeNode $node, string $newname){
730                //This is tricky operation because neither .NET registry API nor Win32 ASPI supports key rename
731                // we must clone the key and then delete original
732                //Create target for copy
733                $newKey = $this->AddKey($node->Parent,$newname,true);    
734                if(is_bool($newKey)) return false;
735                $copyed=false;
736                $this->Cursor = Cursors::$WaitCursor;//Set cursor to hourglass
737                try{
738                    $OldKey=$this->getRegistryKey($node->FullPath,false);//Open source key for reading
739                    $copyed = self::CopyKey($OldKey,$newKey,false);//Copy old key to new key
740                }catch(System:::Exception $ex){
741                    self::OnError($ex->Message);
742                }
743                $this->Cursor = Cursors::$Default;//Reset cursor back to normal
744                $OldKey->Close();//Closing old key is necessary to be done explicitly (PHP closes IDisposable for you somewhen), but open key cannot be deleted
745                unset($OldKey);
746                if($copyed):
747                    try{
748                        $pathparts = explode("\\",$node->FullPath);
749                        //Open old key's parent
750                        $parent = $this->getRegistryKey(System:::String::Join("\\",$pathparts,0,count($pathparts)-1),true);
751                        $parent->DeleteSubKeyTree($node->Name);//delete old key
752                    }catch(System:::Exception $ex){
753                        //Delete failed - now we have two identical keys, super :-(
754                        $TwoKeys=true;
755                        if(isset($parent)):
756                            //When we're puzzled, puzzle user as well - let him decide
757                            if(self::OnError(Program::$Resources->e_DeleteOriginalKey.":\r\n$ex->Message\r\n".Program::$Resources->KeepBoth."\r\n".Program::$Resources->KeepBoth_note,MessageBoxButtons::YesNo)<>DialogResult::Yes):
758                                try{//Delete old key
759                                    $parent->DeleteSubKeyTree($newname);
760        

Large files files are truncated, but you can click here to view the full file