001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj.cpp.mfc;
032
033import org.bridj.BridJ;
034import org.bridj.Callback;
035import org.bridj.NativeObject;
036import org.bridj.Pointer;
037import org.bridj.util.Utils;
038import org.bridj.cpp.CPPRuntime;
039
040import java.lang.reflect.Method;
041import java.lang.reflect.Type;
042import java.util.HashSet;
043import java.util.Map;
044import java.util.Set;
045
046/**
047 *
048 * @author Olivier
049 */
050public class MFCRuntime extends CPPRuntime {
051
052    Method mfcGetMessageMap;
053    String mfcGetMessageMapMangling;
054    Callback mfcGetMessageMapCallback;
055    Set<Class<?>> hasMessageMap = new HashSet<Class<?>>();
056
057    @Override
058    public <T extends NativeObject> Class<? extends T> getActualInstanceClass(Pointer<T> pInstance, Type officialType) {
059        Class officialTypeClass = Utils.getClass(officialType);
060        // For MFC classes, use GetRuntimeClass()
061        if (CObject.class.isAssignableFrom(officialTypeClass)) {
062            Pointer<CRuntimeClass> pClass = new CObject((Pointer) pInstance, this).GetRuntimeClass();
063            if (pClass != null) {
064                CRuntimeClass rtc = pClass.get();
065                try {
066                    Class<? extends T> type = (Class) getMFCClass(rtc.m_lpszClassName());
067                    if (officialTypeClass == null || officialTypeClass.isAssignableFrom(type)) {
068                        return type;
069                    }
070                } catch (ClassNotFoundException ex) {
071                }
072                return officialTypeClass;
073            }
074        }
075
076        // TODO Auto-generated method stub
077        return super.getActualInstanceClass(pInstance, officialType);
078    }
079
080    private Class<?> getMFCClass(Pointer<Byte> mLpszClassName) throws ClassNotFoundException {
081        throw new ClassNotFoundException(mLpszClassName.getCString());
082    }
083
084    public void getExtraFieldsOfNewClass(Class<?> type, Map<String, Type> out) {
085        //super.getExtraFieldsOfNewClass(type, out);
086        if (!hasMessageMap.contains(type)) {
087            return;
088        }
089
090        out.put("messageMap", Pointer.class);
091    }
092
093    public void getOverriddenVirtualMethods(Map<String, Pointer<?>> out) {
094        //super.getVirtualMethodBindings(out);
095        out.put("mfcGetMessageMap", Pointer.getPointer(mfcGetMessageMapCallback));
096    }
097
098    @Override
099    public void register(Type type) {
100        super.register(type);
101        Class typeClass = Utils.getClass(type);
102
103        MessageMapBuilder map = new MessageMapBuilder();
104        for (Method method : typeClass.getMethods()) {
105
106            OnCommand onCommand = method.getAnnotation(OnCommand.class);
107            if (onCommand != null) {
108                map.add(method, onCommand);
109            }
110
111            OnCommandEx onCommandEx = method.getAnnotation(OnCommandEx.class);
112            if (onCommandEx != null) {
113                map.add(method, onCommandEx);
114            }
115
116            OnUpdateCommand onUpdateCommand = method.getAnnotation(OnUpdateCommand.class);
117            if (onUpdateCommand != null) {
118                map.add(method, onUpdateCommand);
119            }
120
121            OnRegisteredMessage onRegisteredMessage = method.getAnnotation(OnRegisteredMessage.class);
122            if (onRegisteredMessage != null) {
123                map.add(method, onRegisteredMessage);
124            }
125
126            OnMessage onMessage = method.getAnnotation(OnMessage.class);
127            if (onMessage != null) {
128                map.add(method, onMessage);
129            }
130        }
131        if (!map.isEmpty()) {
132            map.register(this, typeClass);
133        }
134
135    }
136}