I have a module that I've activated, but it does not show up in the disabled blocks list.
The module is named "My Module"
Inside the my_module folder I have:
my_module.module
my_module.info
my_module.info:
name = My Module
description = My module description.
core = 6.x
package = My Modules
my_module.module
<?php
function hook_block($op = 'list', $delta = 0, $edit = array()){
switch ($op) {
case 'list':
$block = array();
//List out all blocks you want to create here
$block[0]["info"] = t('Display info');
break;
case 'view':
switch ($delta) {
case 0:
$block['subject'] = "ADMIN Header of the block";
global $user;
if(in_array('Site admin', array_values($user->roles) || $user->uid == 1)){
$block['content'] = "input form";
$block['subject'] = "Header of the block";
}
break;
}
}
}
?>
You're not returning any values in your hook call. You'll need to return the array for it to be displayed. I also never tend to use break; when writing implementations of hook_block either.
Try removing the break; and adding return $block; at the end of both cases.
e.g
case 'list':
$block = array();
//List out all blocks you want to create here
$block[0]["info"] = t('Display info');
return $block;
and
case 'view':
switch ($delta) {
case 0:
$block['subject'] = "ADMIN Header of the block";
global $user;
if(in_array('Site admin', array_values($user->roles) || $user->uid == 1)){
$block['content'] = "input form";
$block['subject'] = "Header of the block";
}
return $block;
I'm sure you've seen it, but this might be beneficial to others http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_block/6
Related
i've got this in a file called voting_Request.js:
else
{
count1 = 0;
count2 = 0;
boolCheck = true;
module.exports.count1 = count1;
module.exports.count2 = count2;
}
and i've got this as well in a file called vote.js:
var request = require('./voting_Request.js');
async run(message,args){
var c1 = request.count1;
var c2 = request.count2;
if(!request.boolCheck){
message.reply('No ongoing votings please try again when a voting is available');
}
else{
if(request.voted.indexOf(message.author.tag) > -1){
message.reply("You have already voted!");
}
else{
request.noVote = false;
switch (args) {
case '1':
c1++;
message.reply('Thanks for voting!');
request.voted.push(message.author.tag);
break;
case '2':
c2++;
message.reply('Thanks for voting!');
request.voted.push(message.author.tag);
break;
default:
message.reply(args + ' is not an available option');
}
module.exports.c1 = c1;
module.exports.c2 = c2;
}
}
}
and basicallyinstead of taking the VALUE of count1 and count2 from the request file and only copying it into new variables in vote.js, i want to modify them from vote.js but the value in count1 and count2 will change depending on vote.js.
Thanks for the help!
I have written quite a few different add-ins now but I keep struggling to get a windows form working on Revit. The program builds fine and I have the dll set up for Revit to access.
Here are the different sections of my code. The program is more extensive than what is seen but I believe that the problem is a reference issue or a problem with my ADDIN file. Maybe there is a different way I need to set up my ADDIN file since I have a windows form in it?? Let me know.
Here is a Dropbox folder with the screenshots in it.
Let me know if there is anything else you need to see. The error in Revit says it has to do with the FullName but I believe I put it in the ADDIN file correctly, and I did it the same as I had for other ADDINs.
Thank you for your help!
[TransactionAttribute(TransactionMode.Manual)]
[RegenerationAttribute(RegenerationOption.Manual)]
public class CicuitChecker : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
//set document variable
Document document = commandData.Application.ActiveUIDocument.Document;
using (Transaction trans = new Transaction(document))
{
trans.Start("Circuit Checker");
UIApplication uiApp = commandData.Application;
Document doc = uiApp.ActiveUIDocument.Document;
//run through looped form in case of user not selecting needed fields, and store what family the user wants the program to check
Boolean messedUp = false;
Boolean All = false, lightF = false, recep = false, elecEquip = false, equipCon = false, junc = false, panels = false;
FilteredElementCollector collector = new FilteredElementCollector(doc), collector2 = new FilteredElementCollector(doc);
while (messedUp)
{
CircuitChecker.CircuitCheckerForm form = new CircuitChecker.CircuitCheckerForm();
form.ShowDialog();
//Get application and document objects
foreach (String item in form.getSelectionElementsLB())
{
if (item.Equals("All"))
{
All = true;
break;
}
else if (item.Equals("Lighting Fixtures"))
{
lightF = true;
}
else if (item.Equals("Recepticales"))
{
recep = true;
}
else if (item.Equals("Electrical Equipment (including Panels)"))
{
elecEquip = true;
}
else if (item.Equals("Junctions"))
{
junc = true;
}
else
{
messedUp = true;
TaskDialog.Show("Error", "At least one element must be selected.");
}
}
if (form.getSelectionPlaceLB().Equals("Entire Project"))
{
collector
= new FilteredElementCollector(doc)
.WhereElementIsNotElementType();
collector2
= new FilteredElementCollector(doc)
.WhereElementIsNotElementType();
}
else if (form.getSelectionPlaceLB().Equals("Elements in Current View"))
{
collector
= new FilteredElementCollector(doc, document.ActiveView.Id)
.WhereElementIsNotElementType();
collector2
= new FilteredElementCollector(doc, document.ActiveView.Id)
.WhereElementIsNotElementType();
}
else
{
messedUp = true;
TaskDialog.Show("Error", "A place must be selected.");
}
}
Color color = new Color(138, 43, 226); // RGB
OverrideGraphicSettings ogs = new OverrideGraphicSettings();
OverrideGraphicSettings ogsOriginal = new OverrideGraphicSettings();
ogs.SetProjectionLineColor(color);
int notCircuited = 0;
//ElementId symbolId = family
ElementCategoryFilter lightFilter = new ElementCategoryFilter(BuiltInCategory.OST_LightingFixtures);
ElementCategoryFilter recepFilter = new ElementCategoryFilter(BuiltInCategory.OST_ElectricalFixtures);
ElementCategoryFilter elecEquipFilter = new ElementCategoryFilter(BuiltInCategory.OST_ElectricalEquipment);
//ElementClassFilter filter = new ElementClassFilter(typeof("Junction Boxes - Load"));
//FamilyInstanceFilter juncFilter1 = new FamilyInstanceFilter(doc, );
LogicalOrFilter first = new LogicalOrFilter(lightFilter, recepFilter);
if (All)
{
collector.WherePasses(first);
IList<Element> allArr = collector.ToElements();
foreach (Element e in allArr)
{
int cirNum = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER).AsInteger();
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM).AsString();
if (!(IsNumeric(cirNum)) || (panel.Equals("")) || (panel.Equals("<unnamed>")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
collector2.WherePasses(elecEquipFilter);
IList<Element> elecEquipArr = collector.ToElements();
foreach (Element e in elecEquipArr)
{
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_PANEL_SUPPLY_FROM_PARAM).AsString();
if ((panel.Equals("")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
TaskDialog.Show("Circuit Checker", notCircuited + " lighting fixtures are not circuited in this view.");
trans.Commit();
}
if (!trans.HasEnded())
{
if (lightF)
{
collector.WherePasses(lightFilter);
IList<Element> lightArr = collector.ToElements();
foreach (Element e in lightArr)
{
int cirNum = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER).AsInteger();
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM).AsString();
if (!(IsNumeric(cirNum)) || (panel.Equals("")) || (panel.Equals("<unnamed>")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
}
if (recep)
{
collector.WherePasses(recepFilter);
IList<Element> recepArr = collector.ToElements();
foreach (Element e in recepArr)
{
int cirNum = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER).AsInteger();
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM).AsString();
if (!(IsNumeric(cirNum)) || (panel.Equals("")) || (panel.Equals("<unnamed>")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
}
if (elecEquip)
{
collector.WherePasses(elecEquipFilter);
IList<Element> elecEquipArr = collector.ToElements();
foreach (Element e in elecEquipArr)
{
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_PANEL_SUPPLY_FROM_PARAM).AsString();
if ((panel.Equals("")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
}
if (junc)
{
collector.WherePasses(recepFilter);
IList<Element> juncArr = collector.ToElements();
foreach (Element e in juncArr)
{
int cirNum = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER).AsInteger();
String panel = e.get_Parameter(BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM).AsString();
if (!(IsNumeric(cirNum)) || (panel.Equals("")) || (panel.Equals("<unnamed>")))
{
doc.ActiveView.SetElementOverrides(e.Id, ogs);
notCircuited++;
}
else
{
doc.ActiveView.SetElementOverrides(e.Id, ogsOriginal);
}
}
}
TaskDialog.Show("Circuit Checker", notCircuited + " lighting fixtures are not circuited in this view.");
trans.Commit();
}
}
return Result.Succeeded;
}
public static Boolean IsNumeric(Object Expression)
{
if (Expression == null || Expression is DateTime)
return false;
if (Expression is Int16 || Expression is Int32 || Expression is Int64 || Expression is Decimal || Expression is Single || Expression is Double || Expression is Boolean)
return true;
try
{
if (Expression is string)
Double.Parse(Expression as string);
else
Double.Parse(Expression.ToString());
return true;
}
catch { } // just dismiss errors but return false
return false;
}
}
This code is having the functionality in the 'main class.' I have since moved the functionality to the form class as konrad suggested but am still receiving the FullClassName error in Revit. Please Help!
The schedule data add-in provides a full Visual Studio solution demonstrating how to display a Windows form in a Revit add-in, including the generation of the Windows form on the fly:
http://thebuildingcoder.typepad.com/blog/2012/05/the-schedule-api-and-access-to-schedule-data.html
Here's how I usually set up my Windows Forms based External Commands. Remember that you have to create an External Command, and your addin manifest must point at this class. Then from this class you can launch the Form like so:
[Transaction(TransactionMode.Manual)]
public class SomeCommand : IExternalCommand
{
public Result Execute(
ExternalCommandData commandData,
ref string message,
ElementSet elements)
{
// Get application and document objects
UIApplication uiApp = commandData.Application;
Document doc = uiApp.ActiveUIDocument.Document;
UIDocument uidoc = uiApp.ActiveUIDocument;
try
{
SomeNamespace.SomeForm form = new SomeNamespace.SomeForm(doc);
form.ShowDialog();
return Result.Succeeded;
}
// Catch any exceptions and display them
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
return Result.Cancelled;
}
catch (Exception ex)
{
message = ex.Message;
return Result.Failed;
}
}
}
So I have a Form class that I instantiate from my ExternalCommand and pass Document to its constructor. That way I have access to document when I am interacting with the form later. I wire up all functionality in code behind of the Form.
Agree, the OP's question is why doesn't the addin work...
From looking at the images, it seems like the issue is that Revit is not properly finding the full class name of the command.
It's a little unusual that you don't have your command class wrapped in a namespace (your form class is, for example).
I would recommend wrapping it in a namespace like "circuitchecker" - like your form class.
Then the "full name" in the addin file would become "circuitchecker.circuitchecker"
(the namespace.classname) - this helps Revit distinguish different classes that might have the same name.
side note: I don't believe that putting a URL into the Image/LargeImage fields in the addin will work - but not positive.
I have ClistView control in my MFC application. I need to color some of the items according to its content. For example, if it begins with "No Response to", i need to make it red.
So far, i've tried
BEGIN_MESSAGE_MAP(CMessageView, CListView)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,customDraw)
END_MESSAGE_MAP()
void CMessageView::Update()
{
CListCtrl& refCtrl = GetListCtrl();
refCtrl.InsertItem(LVIF_TEXT|LVIF_PARAM,0,CTime::GetCurrentTime().Format("%H:%M:%S"),0,0,0,42);
refCtrl.SetItemText(0,1,"some text");
refCtrl.SetItemText(0,2,"No response to open");
}
void CMessageView::customDraw(NMHDR * pNMHDR, LRESULT * pResult)
{
_ASSERTE(*pResult == 0);
NMLVCUSTOMDRAW * pnmlvcd = (NMLVCUSTOMDRAW *)pNMHDR;
DWORD dwDrawStage = pnmlvcd->nmcd.dwDrawStage;
BOOL bSubItem = dwDrawStage & CDDS_SUBITEM;
dwDrawStage &= ~CDDS_SUBITEM;
switch (dwDrawStage)
{
case CDDS_PREPAINT:
{
*pResult = CDRF_NOTIFYITEMDRAW;
break;
}
case CDDS_ITEMPREPAINT:
case CDDS_SUBITEM:
{
if(pnmlvcd->nmcd.lItemlParam == 42)
{
pnmlvcd->clrText = RGB(255,0,0);
}
*pResult = 0;
break;
}
default:
{
*pResult = 0;
break;
}
}
}
But it does not work. The color does not change. Am i missing something or doing something wrong?
If you have VS2008 SP1, it's much easier to use CMFCListCtrl instead - it has virtual functions you can override to set the foreground and background colours of each row.
This code in a simple example application worked for me. My list control has two columns and two items. The second item, second column has item data set to 42, in this case, only that particular subitem had the text changed to red.
void CMFCTestDlg::OnNMCustomdrawList1(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );
// TODO: Add your control notification handler code here
*pResult = CDRF_DODEFAULT;
switch(pLVCD->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW;
break;
case CDDS_ITEMPREPAINT:
*pResult = CDRF_NOTIFYSUBITEMDRAW;
break;
case (CDDS_ITEMPREPAINT | CDDS_SUBITEM):
{
if(1 == pLVCD->iSubItem)
{
if(pLVCD->nmcd.lItemlParam == 42)
{
pLVCD->clrText = RGB(255, 0, 0);
}
}
}
break;
}
}
I am using the below code to determine the activation of the Widnows7. I am getting 7 instances/product. I am not clear which product refers to original Windows 7.
I am unable to find documentation on to check which instance to determine whether Windows is activated or not
//use a SelectQuery to tell what we're searching in
SelectQuery searchQuery = new SelectQuery("SELECT * FROM SoftwareLicensingProduct");
//set the search up
ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(scope, searchQuery);
//get the results into a collection
using (ManagementObjectCollection obj = searcherObj.Get())
{
foreach (ManagementObject m in obj)
{
if (Convert.ToInt32(m["GracePeriodRemaining"].ToString()) == 0)
{
MessageBox.Show("Windows is active");
break;
}
else
{
MessageBox.Show(" Windows is not active");
break;
}
}
//now loop through the collection looking for
//an activation status
}
When you use the SoftwareLicensingProduct WMI class, more than an instance is returned due to the Volume Licensing feature introduced in Windows Vista, so to return only the instance of you Windows version you must filter the WQL sentence using the PartialProductKey, ApplicationId and LicenseIsAddon properties.
Try this sample
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
string ComputerName = "localhost";
ManagementScope Scope;
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT * FROM SoftwareLicensingProduct Where PartialProductKey <> null AND ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f' AND LicenseIsAddon=False");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}", "Name", (String)WmiObject["Name"]);
Console.WriteLine("{0,-35} {1,-40}", "GracePeriodRemaining", (UInt32) WmiObject["GracePeriodRemaining"]);// Uint32
switch ((UInt32)WmiObject["LicenseStatus"])
{
case 0: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "Unlicensed");
break;
case 1: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "Licensed");
break;
case 2: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "Out-Of-Box Grace Period");
break;
case 3: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "Out-Of-Tolerance Grace Period");
break;
case 4: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "on-Genuine Grace Period");
break;
case 5: Console.WriteLine("{0,-35} {1,-40}", "LicenseStatus", "Notification");
break;
}
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
Another option is use the SLIsGenuineLocal function.
Try the answer to this question Determine Genuine Windows Installation in C# for a C# sample.
Windows® 7, VOLUME_KMSCLIENT channel refers to the actual product. this can found in description property
string ComputerName = "localhost";
ManagementScope Scope;
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);
Scope.Connect();
SelectQuery searchQuery = new SelectQuery("SELECT * FROM SoftwareLicensingProduct");
//set the search up
ManagementObjectSearcher searcherObj = new ManagementObjectSearcher(Scope, searchQuery);
//get the results into a collection
using (ManagementObjectCollection obj = searcherObj.Get())
{
foreach (ManagementObject m in obj)
{
String s = m["Description"].ToString();
if ((m["Description"].ToString()) .Contains("VOLUME_KMSCLIENT channel"))
{
if (m["LicenseStatus"].ToString() == "1")
{
var gracePeriod = Convert.ToInt32(m["GracePeriodRemaining"]) / (60 * 24);
MessageBox.Show("Not Licensed " + " Grace Period Remaining--" + gracePeriod.ToString() + "days");
}
else
{
var gracePeriod = Convert.ToInt32(m["GracePeriodRemaining"]) / (60 * 24);
MessageBox.Show("Not Licensed " + " Grace Period Remaining--" + gracePeriod.ToString() + "days");
}
}
}
}
how to differentiate a Folder Type(Windows/FTP) in MFC(VC++)?
In my case I have a MFC Treeview in which i am adding list of folders coming from server , that folders are Windows and CIFS .Now i want to differentiate internally what type of folder are they because i select some folder and say connect then it brings up login page where i need to login credentials details , but before that i need to differentiate what type of folder is that ?
Any treeview property like setting and geeting key or any other approach.
Thanks in Advance.
I get folder list from server in this format volume1/Folder1,volume2/Folder2||Folder3,Folder4 in this below method i am removing "||" and maintaining them in two differnt variables: strDataFolder contains - FTP Folders and
strNASfolders conatins CIFS folder , then one more method i am using UpdateFolder. If it is FTP then directly Add but if it CIFS check for duplication if that folder is already there dont add it again to treeview.
Now iam not able to get it how to differentiate what type of folder are they ?
void CNDSClientDlg::UpdateSharedFolder(CString strNASfolders,HTREEITEM hChildItem)
{
CString strDataFolder = "";
CString strData = "";
int iPos = 0;
int fPosition = 0;
fPosition = strNASfolders.Find("||");
if(fPosition != -1)
{
strDataFolder = strNASfolders.Mid(0,fPosition);
strNASfolders = strNASfolders.Right(strNASfolders.GetLength()-(fPosition+2));
}
else
{
strDataFolder = strNASfolders;
}
if (strDataFolder != "" )
{
UpdateFolders(strDataFolder,hChildItem,false);
}
if (strNASfolders != "" ) //don't add if already exist
{
UpdateFolders(strNASfolders,hChildItem,true);
}
}
void CNDSClientDlg::UpdateFolders(CString strFolderType,HTREEITEM hChildItem,bool bCheck)
{
int iPos = 0 ;
CString strData = "";
CString strCurrFolder ="";
HTREEITEM HShareFolder = NULL;
bool bFound = false ;
while (iPos != -1)
{
iPos = strFolderType.Find(",");
if (iPos != -1)
{
strData = strFolderType.Mid(0,iPos);//get the folder details
}
else
{
strData = strFolderType;//get the last folder details
}
strFolderType = strFolderType.Right(strFolderType.GetLength()-(iPos+1)); //get remaining data
int fPos = strData.ReverseFind('/');
if (fPos != -1)
{
strCurrFolder = strData.Mid(fPos+1,strData.GetLength()); // get required data
}
else
{
strCurrFolder = strData; //else assign all the data
}
if(bCheck == true)
{
bFound = false ;
HTREEITEM hTempItem = NULL;
CString strItemText = "" ;
hTempItem = m_pTreeview->GetChildItem(hChildItem);
strItemText = m_pTreeview->GetItemText(hTempItem);
while(hTempItem != NULL)
{
if(strItemText != strCurrFolder)
{
strItemText = m_pTreeview->GetItemText(hTempItem);
hTempItem = m_pTreeview->GetNextSiblingItem(hTempItem);
}
else
{
bFound = true;
break;
}
}
}
if(bCheck == false || bFound == false)
{
HShareFolder = m_pTreeview->InsertItem(strCurrFolder,hChildItem);
m_pTreeview->SetItemImage(HShareFolder,2,2);
TTipItemData* pToolTipData ;
pToolTipData = new TTipItemData;
pToolTipData->strTool = strData ;
m_pTreeview->SetItemData(HShareFolder,DWORD(pToolTipData));
}
m_pTreeview->Expand(hParentItem,TVE_EXPAND);
m_pTreeview->EnsureVisible(hParentItem);
}
}
Items in treeviews can have arbitrary data associated with them. Check out:
http://msdn.microsoft.com/en-us/library/ettyybhw(VS.80).aspx
The InsertItem method shown here has an LPARAM parameter. This is for your use, and you can set this to some value that is meaningful to your application.
(EDIT: Alternatively, use one of the least convoluted overloads to insert your item and use CTreeCtrl::SetItemData on the handle that is returned afterwards).
To find out what value is associated with your item, use CTreeCtrl::GetItemData.
Minor Example:
HTREEITEM hItem = m_ctrlTree.InsertItem("My Item", TVI_ROOT);
HTREEITEM hOther = m_ctrlTree.InsertItem("Child Item", hItem);
m_ctrlTree.SetItemData(hItem, static_cast<DWORD_PTR>(10)); // set LPARAM to 10
// note, you can also store pointers! This assumes pObj is some kind of instance
// of a class.
m_ctrlTree.SetItemData(hOther, static_cast<DWORD_PTR>(pObj));
// at a later point:
int myVal = static_cast<int>(m_ctrlTree.GetItemData(hItem));
MyObject* pObj = static_cast<MyObject*>(m_ctrlTree.GetItemData(hOther));