2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
35 #include <msclr/marshal.h>
39 using namespace System
;
40 using namespace System::Runtime::InteropServices
;
42 using namespace msclr::interop
;
44 public enum class CecDeviceType
54 public enum class CecLogLevel
65 public enum class CecLogicalAddress
67 Unknown
= -1, //not a valid logical address
87 public enum class CecPowerStatus
91 InTransitionStandbyToOn
= 0x02,
92 InTransitionOnToStandby
= 0x03,
96 public enum class CecVersion
106 public enum class CecDisplayControl
108 DisplayForDefaultTime
= 0x00,
109 DisplayUntilCleared
= 0x40,
110 ClearPreviousMessage
= 0x80,
111 ReservedForFutureUse
= 0xC0
114 public enum class CecMenuState
120 public enum class CecDeckControlMode
123 SkipReverseRewind
= 2,
128 public enum class CecDeckInfo
140 SkipForwardWind
= 0x1B,
141 SkipReverseRewind
= 0x1C,
142 IndexSearchForward
= 0x1D,
143 IndexSearchReverse
= 0x1E,
147 public enum class CecUserControlCode
179 PreviousChannel
= 0x32,
182 DisplayInformation
= 0x35,
203 VideoOnDemand
= 0x52,
204 ElectronicProgramGuide
= 0x53,
205 TimerProgramming
= 0x54,
206 InitialConfiguration
= 0x55,
208 PausePlayFunction
= 0x61,
209 RecordFunction
= 0x62,
210 PauseRecordFunction
= 0x63,
213 RestoreVolumeFunction
= 0x66,
215 SelectMediaFunction
= 0x68,
216 SelectAVInputFunction
= 0x69,
217 SelectAudioInputFunction
= 0x6A,
218 PowerToggleFunction
= 0x6B,
219 PowerOffFunction
= 0x6C,
220 PowerOnFunction
= 0x6D,
231 public enum class CecVendorId
243 public enum class CecAudioStatus
245 MuteStatusMask
= 0x80,
246 VolumeStatusMask
= 0x7F,
249 VolumeStatusUnknown
= 0x7F
252 public enum class CecOpcode
257 InactiveSource
= 0x9D,
258 RequestActiveSource
= 0x85,
259 RoutingChange
= 0x80,
260 RoutingInformation
= 0x81,
261 SetStreamPath
= 0x86,
266 RecordTvScreen
= 0x0F,
267 ClearAnalogueTimer
= 0x33,
268 ClearDigitalTimer
= 0x99,
269 ClearExternalTimer
= 0xA1,
270 SetAnalogueTimer
= 0x34,
271 SetDigitalTimer
= 0x97,
272 SetExternalTimer
= 0xA2,
273 SetTimerProgramTitle
= 0x67,
274 TimerClearedStatus
= 0x43,
277 GetCecVersion
= 0x9F,
278 GivePhysicalAddress
= 0x83,
279 GetMenuLanguage
= 0x91,
280 ReportPhysicalAddress
= 0x84,
281 SetMenuLanguage
= 0x32,
284 GiveDeckStatus
= 0x1A,
286 GiveTunerDeviceStatus
= 0x08,
287 SelectAnalogueService
= 0x92,
288 SelectDigtalService
= 0x93,
289 TunerDeviceStatus
= 0x07,
290 TunerStepDecrement
= 0x06,
291 TunerStepIncrement
= 0x05,
292 DeviceVendorId
= 0x87,
293 GiveDeviceVendorId
= 0x8C,
294 VendorCommand
= 0x89,
295 VendorCommandWithId
= 0xA0,
296 VendorRemoteButtonDown
= 0x8A,
297 VendorRemoteButtonUp
= 0x8B,
303 UserControlPressed
= 0x44,
304 UserControlRelease
= 0x45,
305 GiveDevicePowerStatus
= 0x8F,
306 ReportPowerStatus
= 0x90,
309 GiveAudioStatus
= 0x71,
310 GiveSystemAudioMode
= 0x7D,
311 ReportAudioStatus
= 0x7A,
312 SetSystemAudioMode
= 0x72,
313 SystemAudioModeRequest
= 0x70,
314 SystemAudioModeStatus
= 0x7E,
316 /* when this opcode is set, no opcode will be sent to the device. this is one of the reserved numbers */
320 public enum class CecSystemAudioStatus
326 public ref
class CecAdapter
329 CecAdapter(String
^ strPath
, String
^ strComPort
)
332 ComPort
= strComPort
;
335 property String
^ Path
;
336 property String
^ ComPort
;
339 public ref
class CecDeviceTypeList
342 CecDeviceTypeList(void)
344 Types
= gcnew array
<CecDeviceType
>(5);
345 for (unsigned int iPtr
= 0; iPtr
< 5; iPtr
++)
346 Types
[iPtr
] = CecDeviceType::Reserved
;
349 property array
<CecDeviceType
> ^ Types
;
352 public ref
class CecLogicalAddresses
355 CecLogicalAddresses(void)
357 Addresses
= gcnew array
<CecLogicalAddress
>(16);
358 for (unsigned int iPtr
= 0; iPtr
< 16; iPtr
++)
359 Addresses
[iPtr
] = CecLogicalAddress::Unregistered
;
362 bool IsSet(CecLogicalAddress iAddress
)
364 return Addresses
[(unsigned int)iAddress
] != CecLogicalAddress::Unregistered
;
367 property array
<CecLogicalAddress
> ^ Addresses
;
370 public ref
class CecDatapacket
375 Data
= gcnew array
<uint8_t>(100);
379 void PushBack(uint8_t data
)
388 property array
<uint8_t> ^ Data
;
389 property
uint8_t Size
;
392 public ref
class CecCommand
395 CecCommand(CecLogicalAddress iInitiator
, CecLogicalAddress iDestination
, bool bAck
, bool bEom
, CecOpcode iOpcode
, int32_t iTransmitTimeout
)
397 Initiator
= iInitiator
;
398 Destination
= iDestination
;
403 TransmitTimeout
= iTransmitTimeout
;
404 Parameters
= gcnew CecDatapacket
;
410 Initiator
= CecLogicalAddress::Unknown
;
411 Destination
= CecLogicalAddress::Unknown
;
414 Opcode
= CecOpcode::None
;
417 Parameters
= gcnew CecDatapacket
;
421 void PushBack(uint8_t data
)
423 if (Initiator
== CecLogicalAddress::Unknown
&& Destination
== CecLogicalAddress::Unknown
)
425 Initiator
= (CecLogicalAddress
) (data
>> 4);
426 Destination
= (CecLogicalAddress
) (data
& 0xF);
431 Opcode
= (CecOpcode
)data
;
435 Parameters
->PushBack(data
);
440 property CecLogicalAddress Initiator
;
441 property CecLogicalAddress Destination
;
444 property CecOpcode Opcode
;
445 property CecDatapacket
^ Parameters
;
446 property
bool OpcodeSet
;
447 property
int32_t TransmitTimeout
;
450 public ref
class CecKeypress
453 CecKeypress(int iKeycode
, unsigned int iDuration
)
456 Duration
= iDuration
;
468 property
int Keycode
;
469 property
unsigned int Duration
;
472 public ref
class CecLogMessage
475 CecLogMessage(String
^ strMessage
, CecLogLevel iLevel
, int64_t iTime
)
477 Message
= strMessage
;
486 Level
= CecLogLevel::None
;
492 property String
^ Message
;
493 property CecLogLevel Level
;
494 property
int64_t Time
;
497 public ref
class CecCallbackMethods
500 virtual int ReceiveLogMessage(CecLogMessage
^ message
)
505 virtual int ReceiveKeypress(CecKeypress
^ key
)
510 virtual int ReceiveCommand(CecCommand
^ command
)
517 // unmanaged callback methods
518 typedef int (__stdcall
*LOGCB
) (const cec_log_message
&message
);
519 typedef int (__stdcall
*KEYCB
) (const cec_keypress
&key
);
520 typedef int (__stdcall
*COMMANDCB
)(const cec_command
&command
);
522 static LOGCB g_logCB
;
523 static KEYCB g_keyCB
;
524 static COMMANDCB g_commandCB
;
525 static ICECCallbacks g_cecCallbacks
;
527 int CecLogMessageCB(void *cbParam
, const cec_log_message
&message
)
530 return g_logCB(message
);
534 int CecKeyPressCB(void *cbParam
, const cec_keypress
&key
)
541 int CecCommandCB(void *cbParam
, const cec_command
&command
)
544 return g_commandCB(command
);
549 // delegates for the unmanaged callback methods
550 public delegate
int CecLogMessageManagedDelegate(const cec_log_message
&);
551 public delegate
int CecKeyPressManagedDelegate(const cec_keypress
&);
552 public delegate
int CecCommandManagedDelegate(const cec_command
&);
554 public ref
class LibCecSharp
557 LibCecSharp(String
^ strDeviceName
, CecDeviceTypeList
^ deviceTypes
)
559 marshal_context
^ context
= gcnew
marshal_context();
560 m_bHasCallbacks
= false;
561 const char* strDeviceNameC
= context
->marshal_as
<const char*>(strDeviceName
);
563 cec_device_type_list types
;
564 for (unsigned int iPtr
= 0; iPtr
< 5; iPtr
++)
565 types
.types
[iPtr
] = (cec_device_type
)deviceTypes
->Types
[iPtr
];
566 m_libCec
= (ICECAdapter
*) CECInit(strDeviceNameC
, types
);
568 // create the delegate method for the log message callback
569 m_logMessageDelegate
= gcnew
CecLogMessageManagedDelegate(this, &LibCecSharp::CecLogMessageManaged
);
570 m_logMessageGCHandle
= GCHandle::Alloc(m_logMessageDelegate
);
571 g_logCB
= static_cast<LOGCB
>(Marshal::GetFunctionPointerForDelegate(m_logMessageDelegate
).ToPointer());
572 g_cecCallbacks
.CBCecLogMessage
= CecLogMessageCB
;
574 // create the delegate method for the keypress callback
575 m_keypressDelegate
= gcnew
CecKeyPressManagedDelegate(this, &LibCecSharp::CecKeyPressManaged
);
576 m_keypressGCHandle
= GCHandle::Alloc(m_keypressDelegate
);
577 g_keyCB
= static_cast<KEYCB
>(Marshal::GetFunctionPointerForDelegate(m_keypressDelegate
).ToPointer());
578 g_cecCallbacks
.CBCecKeyPress
= CecKeyPressCB
;
580 // create the delegate method for the command callback
581 m_commandDelegate
= gcnew
CecCommandManagedDelegate(this, &LibCecSharp::CecCommandManaged
);
582 m_commandGCHandle
= GCHandle::Alloc(m_commandDelegate
);
583 g_commandCB
= static_cast<COMMANDCB
>(Marshal::GetFunctionPointerForDelegate(m_commandDelegate
).ToPointer());
584 g_cecCallbacks
.CBCecCommand
= CecCommandCB
;
591 CECDestroy(m_libCec
);
599 CECDestroy(m_libCec
);
605 array
<CecAdapter
^> ^ FindAdapters(String
^ path
)
607 cec_adapter
*devices
= new cec_adapter
[10];
609 marshal_context
^ context
= gcnew
marshal_context();
610 const char* strPathC
= path
->Length
> 0 ? context
->marshal_as
<const char*>(path
) : NULL
;
612 uint8_t iDevicesFound
= m_libCec
->FindAdapters(devices
, 10, NULL
);
614 array
<CecAdapter
^> ^ adapters
= gcnew array
<CecAdapter
^>(iDevicesFound
);
615 for (unsigned int iPtr
= 0; iPtr
< iDevicesFound
; iPtr
++)
616 adapters
[iPtr
] = gcnew
CecAdapter(gcnew
String(devices
[iPtr
].path
), gcnew
String(devices
[iPtr
].comm
));
623 bool Open(String
^ strPort
, int iTimeoutMs
)
625 marshal_context
^ context
= gcnew
marshal_context();
626 const char* strPortC
= context
->marshal_as
<const char*>(strPort
);
627 bool bReturn
= m_libCec
->Open(strPortC
, iTimeoutMs
);
637 bool EnableCallbacks(CecCallbackMethods
^ callbacks
)
639 if (m_libCec
&& !m_bHasCallbacks
)
641 m_bHasCallbacks
= true;
642 m_callbacks
= callbacks
;
643 return m_libCec
->EnableCallbacks(NULL
, &g_cecCallbacks
);
649 bool PingAdapter(void)
651 return m_libCec
->PingAdapter();
654 bool StartBootloader(void)
656 return m_libCec
->StartBootloader();
659 int GetMinLibVersion(void)
661 return m_libCec
->GetMinLibVersion();
664 int GetLibVersionMajor(void)
666 return m_libCec
->GetLibVersionMajor();
669 int GetLibVersionMinor(void)
671 return m_libCec
->GetLibVersionMinor();
674 CecLogMessage
^ GetNextLogMessage(void)
677 if (m_libCec
->GetNextLogMessage(&msg
))
679 return gcnew
CecLogMessage(gcnew
String(msg
.message
), (CecLogLevel
)msg
.level
, msg
.time
);
682 return gcnew
CecLogMessage();
685 CecKeypress
^ GetNextKeypress(void)
688 if (m_libCec
->GetNextKeypress(&key
))
690 return gcnew
CecKeypress(key
.keycode
, key
.duration
);
693 return gcnew
CecKeypress();
696 CecCommand
^ GetNextCommand(void)
699 if (m_libCec
->GetNextCommand(&command
))
701 CecCommand
^ retVal
= gcnew
CecCommand((CecLogicalAddress
)command
.initiator
, (CecLogicalAddress
)command
.destination
, command
.ack
== 1 ? true : false, command
.eom
== 1 ? true : false, (CecOpcode
)command
.opcode
, command
.transmit_timeout
);
702 for (uint8_t iPtr
= 0; iPtr
< command
.parameters
.size
; iPtr
++)
703 retVal
->Parameters
->PushBack(command
.parameters
[iPtr
]);
707 return gcnew
CecCommand();
710 bool Transmit(CecCommand
^ command
)
712 cec_command ccommand
;
713 cec_command::Format(ccommand
, (cec_logical_address
)command
->Initiator
, (cec_logical_address
)command
->Destination
, (cec_opcode
)command
->Opcode
);
714 ccommand
.transmit_timeout
= command
->TransmitTimeout
;
715 ccommand
.eom
= command
->Eom
;
716 ccommand
.ack
= command
->Ack
;
717 for (unsigned int iPtr
= 0; iPtr
< command
->Parameters
->Size
; iPtr
++)
718 ccommand
.parameters
.PushBack(command
->Parameters
->Data
[iPtr
]);
720 return m_libCec
->Transmit(ccommand
);
723 bool SetLogicalAddress(CecLogicalAddress logicalAddress
)
725 return m_libCec
->SetLogicalAddress((cec_logical_address
) logicalAddress
);
728 bool SetPhysicalAddress(int16_t physicalAddress
)
730 return m_libCec
->SetPhysicalAddress(physicalAddress
);
733 bool PowerOnDevices(CecLogicalAddress logicalAddress
)
735 return m_libCec
->PowerOnDevices((cec_logical_address
) logicalAddress
);
738 bool StandbyDevices(CecLogicalAddress logicalAddress
)
740 return m_libCec
->StandbyDevices((cec_logical_address
) logicalAddress
);
743 bool PollDevice(CecLogicalAddress logicalAddress
)
745 return m_libCec
->PollDevice((cec_logical_address
) logicalAddress
);
748 bool SetActiveSource(CecDeviceType type
)
750 return m_libCec
->SetActiveSource((cec_device_type
) type
);
753 bool SetDeckControlMode(CecDeckControlMode mode
, bool sendUpdate
)
755 return m_libCec
->SetDeckControlMode((cec_deck_control_mode
) mode
, sendUpdate
);
758 bool SetDeckInfo(CecDeckInfo info
, bool sendUpdate
)
760 return m_libCec
->SetDeckInfo((cec_deck_info
) info
, sendUpdate
);
763 bool SetInactiveView(void)
765 return m_libCec
->SetInactiveView();
768 bool SetMenuState(CecMenuState state
, bool sendUpdate
)
770 return m_libCec
->SetMenuState((cec_menu_state
) state
, sendUpdate
);
773 bool SetOSDString(CecLogicalAddress logicalAddress
, CecDisplayControl duration
, String
^ message
)
775 marshal_context
^ context
= gcnew
marshal_context();
776 const char* strMessageC
= context
->marshal_as
<const char*>(message
);
778 bool bReturn
= m_libCec
->SetOSDString((cec_logical_address
) logicalAddress
, (cec_display_control
) duration
, strMessageC
);
784 bool SwitchMonitoring(bool enable
)
786 return m_libCec
->SwitchMonitoring(enable
);
789 CecVersion
GetDeviceCecVersion(CecLogicalAddress logicalAddress
)
791 return (CecVersion
) m_libCec
->GetDeviceCecVersion((cec_logical_address
) logicalAddress
);
794 String
^ GetDeviceMenuLanguage(CecLogicalAddress logicalAddress
)
796 cec_menu_language lang
;
797 if (m_libCec
->GetDeviceMenuLanguage((cec_logical_address
) logicalAddress
, &lang
))
799 return gcnew
String(lang
.language
);
802 return gcnew
String("");
805 CecVendorId
GetDeviceVendorId(CecLogicalAddress logicalAddress
)
807 return (CecVendorId
)m_libCec
->GetDeviceVendorId((cec_logical_address
) logicalAddress
);
810 CecPowerStatus
GetDevicePowerStatus(CecLogicalAddress logicalAddress
)
812 return (CecPowerStatus
) m_libCec
->GetDevicePowerStatus((cec_logical_address
) logicalAddress
);
815 CecLogicalAddresses
^ GetActiveDevices(void)
817 CecLogicalAddresses
^ retVal
= gcnew
CecLogicalAddresses();
818 unsigned int iDevices
= 0;
820 cec_logical_addresses activeDevices
= m_libCec
->GetActiveDevices();
822 for (uint8_t iPtr
= 0; iPtr
< 16; iPtr
++)
823 if (activeDevices
[iPtr
])
824 retVal
->Addresses
[iDevices
++] = (CecLogicalAddress
)iPtr
;
829 bool IsActiveDevice(CecLogicalAddress logicalAddress
)
831 return m_libCec
->IsActiveDevice((cec_logical_address
)logicalAddress
);
834 bool IsActiveDeviceType(CecDeviceType type
)
836 return m_libCec
->IsActiveDeviceType((cec_device_type
)type
);
839 bool SetHDMIPort(CecLogicalAddress address
, uint8_t port
)
841 return m_libCec
->SetHDMIPort((cec_logical_address
)address
, port
);
844 uint8_t VolumeUp(bool wait
)
846 return m_libCec
->VolumeUp(wait
);
849 uint8_t VolumeDown(bool wait
)
851 return m_libCec
->VolumeDown(wait
);
854 uint8_t MuteAudio(bool wait
)
856 return m_libCec
->MuteAudio(wait
);
859 bool SendKeypress(CecLogicalAddress destination
, CecUserControlCode key
, bool wait
)
861 return m_libCec
->SendKeypress((cec_logical_address
)destination
, (cec_user_control_code
)key
, wait
);
864 bool SendKeyRelease(CecLogicalAddress destination
, bool wait
)
866 return m_libCec
->SendKeyRelease((cec_logical_address
)destination
, wait
);
869 String
^ GetDeviceOSDName(CecLogicalAddress logicalAddress
)
871 cec_osd_name osd
= m_libCec
->GetDeviceOSDName((cec_logical_address
) logicalAddress
);
872 return gcnew
String(osd
.name
);
875 CecLogicalAddress
GetActiveSource()
877 return (CecLogicalAddress
)m_libCec
->GetActiveSource();
880 bool IsActiveSource(CecLogicalAddress logicalAddress
)
882 return m_libCec
->IsActiveSource((cec_logical_address
)logicalAddress
);
885 uint16_t GetDevicePhysicalAddress(CecLogicalAddress iAddress
)
887 return m_libCec
->GetDevicePhysicalAddress((cec_logical_address
)iAddress
);
890 String
^ ToString(CecLogicalAddress iAddress
)
892 const char *retVal
= m_libCec
->ToString((cec_logical_address
)iAddress
);
893 return gcnew
String(retVal
);
896 String
^ ToString(CecVendorId iVendorId
)
898 const char *retVal
= m_libCec
->ToString((cec_vendor_id
)iVendorId
);
899 return gcnew
String(retVal
);
902 String
^ ToString(CecVersion iVersion
)
904 const char *retVal
= m_libCec
->ToString((cec_version
)iVersion
);
905 return gcnew
String(retVal
);
908 String
^ ToString(CecPowerStatus iState
)
910 const char *retVal
= m_libCec
->ToString((cec_power_status
)iState
);
911 return gcnew
String(retVal
);
914 String
^ ToString(CecMenuState iState
)
916 const char *retVal
= m_libCec
->ToString((cec_menu_state
)iState
);
917 return gcnew
String(retVal
);
920 String
^ ToString(CecDeckControlMode iMode
)
922 const char *retVal
= m_libCec
->ToString((cec_deck_control_mode
)iMode
);
923 return gcnew
String(retVal
);
926 String
^ ToString(CecDeckInfo status
)
928 const char *retVal
= m_libCec
->ToString((cec_deck_info
)status
);
929 return gcnew
String(retVal
);
932 String
^ ToString(CecOpcode opcode
)
934 const char *retVal
= m_libCec
->ToString((cec_opcode
)opcode
);
935 return gcnew
String(retVal
);
938 String
^ ToString(CecSystemAudioStatus mode
)
940 const char *retVal
= m_libCec
->ToString((cec_system_audio_status
)mode
);
941 return gcnew
String(retVal
);
944 String
^ ToString(CecAudioStatus status
)
946 const char *retVal
= m_libCec
->ToString((cec_audio_status
)status
);
947 return gcnew
String(retVal
);
951 void DestroyDelegates()
953 m_logMessageGCHandle
.Free();
954 m_keypressGCHandle
.Free();
955 m_commandGCHandle
.Free();
958 // managed callback methods
959 int CecLogMessageManaged(const cec_log_message
&message
)
963 iReturn
= m_callbacks
->ReceiveLogMessage(gcnew
CecLogMessage(gcnew
String(message
.message
), (CecLogLevel
)message
.level
, message
.time
));
967 int CecKeyPressManaged(const cec_keypress
&key
)
971 iReturn
= m_callbacks
->ReceiveKeypress(gcnew
CecKeypress(key
.keycode
, key
.duration
));
975 int CecCommandManaged(const cec_command
&command
)
980 CecCommand
^ newCommand
= gcnew
CecCommand((CecLogicalAddress
)command
.initiator
, (CecLogicalAddress
)command
.destination
, command
.ack
== 1 ? true : false, command
.eom
== 1 ? true : false, (CecOpcode
)command
.opcode
, command
.transmit_timeout
);
981 for (uint8_t iPtr
= 0; iPtr
< command
.parameters
.size
; iPtr
++)
982 newCommand
->Parameters
->PushBack(command
.parameters
[iPtr
]);
983 iReturn
= m_callbacks
->ReceiveCommand(newCommand
);
988 ICECAdapter
* m_libCec
;
989 CecCallbackMethods
^ m_callbacks
;
990 bool m_bHasCallbacks
;
992 CecLogMessageManagedDelegate
^ m_logMessageDelegate
;
993 static GCHandle m_logMessageGCHandle
;
994 LOGCB m_logMessageCallback
;
996 CecKeyPressManagedDelegate
^ m_keypressDelegate
;
997 static GCHandle m_keypressGCHandle
;
998 KEYCB m_keypressCallback
;
1000 CecCommandManagedDelegate
^ m_commandDelegate
;
1001 static GCHandle m_commandGCHandle
;
1002 COMMANDCB m_commandCallback
;