将GMap封装为Activex供QT使用(工具:VS2017,QT5.12)

Posted baqifanye

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将GMap封装为Activex供QT使用(工具:VS2017,QT5.12)相关的知识,希望对你有一定的参考价值。

由于一开始定的开发平台在QT下,到后面要加入地图控件.qt里本身带有地图qmap(在qt的官方案例中可以找到,用qml做的),但只有固定的几个地图源,要做google或者bing地图,时间和人力不允许,而且对地图也不是很熟悉..就决定先用gmap.

思路:

   gmap 是用c#开发的,像QT这种C++语言类无法直接使用,固将gmap 以com组件的形式封装成控件,供c++使用;

1.以管理员模式身份打开vs2017-文件-新建-项目-创建 Windows窗体控件库

技术图片

 

框架可根据情况自行选择;   确定;

2.这时候就出现控件窗体了,可以更一下文件名

技术图片

 

3. 工程属性设置    勾选 使程序集COM可见 ,勾选 为COM互操作可见 (其作用在于在程序编译后,不需要再安装com组件,如不是管理员身体启动vs,勾选它在编译时会报无权限错误)

  技术图片

技术图片

 

 

 

 

 

4.添加gmap引用,我这里使用 NuGet 来添加....项目---管理NuGet程序包    浏览 搜索 gmap  点击 安装   

技术图片

 

5.安装完后 添加gmap控件到 控件窗体 

  在工具箱 找到GmapControl 拖到控件窗体

  如果找不到 GmapControl  控件,, 需手动添加gmapcontrol控件 

       在工具箱空白处右键 打开 选择项    浏览到本项目解决方案下,有个packages 文件名,就是gmap的引用包,,浏览找到 GMap.NET.WindowsForms.dll 添加 即可.....这时工具箱内就会有GmapControl了

技术图片

 

 技术图片

技术图片

 

6.将 GmapControl 添加到窗体后,默认名为 gMapControl1  可自行更改 ..... 在  gMapControl1 控件上双击  添加以下代码 

需添加引用

using GMap.NET.MapProviders;
using GMap.NET;

  

this.gMapControl1.CacheLocation = System.Windows.Forms.Application.StartupPath;//缓存文件路径
            this.gMapControl1.MapProvider = GMapProviders.BingHybridMap;
            this.gMapControl1.Manager.Mode = AccessMode.ServerAndCache;//地图模式为本地缓存,完全离线

            this.gMapControl1.ShowCenter = true;//隐藏或显示中心十字
            this.gMapControl1.MinZoom = 1;
            this.gMapControl1.MaxZoom = 23;
            this.gMapControl1.Zoom = 12;
            //this.gMapControl.ShowTileGridLines = false;//道路网格线
            this.gMapControl1.DragButton = System.Windows.Forms.MouseButtons.Left;//左健拖动地图
            this.gMapControl1.MouseWheelZoomType = MouseWheelZoomType.MousePositionWithoutCenter;//不以中心点缩放
            this.gMapControl1.Position = new PointLatLng(34.2313041, 108.8774211);

  

7,添加一个新的接口 IObjectSafety.cs

技术图片

 

   代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices; //需手动添加的

namespace TestLibrary
{
    //以下代码可完全复制过去,不做任何改动,Guid 也不需要更改
    [ComImport, Guid("1D9AD540-F2C9-4368-8697-C4AAFCCE9C55")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IObjectSafety
    {
        [PreserveSig]
        int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);

        [PreserveSig()]
        int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);

    }
}

 

在AssemblyInfo.cs 文件中 添加  using System.Security;  和  [assembly: AllowPartiallyTrustedCallers()]

 

8,返回到  MapLibrary.cs , 给MapLibrary添加父类 IObjectSafety ,,,添加Guid (在工具--创建Guid   这个小工具里生成)

 并添加代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using GMap.NET.MapProviders;
using GMap.NET;
using System.Runtime.InteropServices;

namespace TestLibrary
{
    [Guid("0E32CE01-4D40-45A6-8B59-B39ABFE8ADB0")]
    public partial class MapLibrary: UserControl, IObjectSafety //接口类的引用
    {
        public MapLibrary()
        {
            InitializeComponent();
        }

        private void gMapControl1_Load(object sender, EventArgs e)
        {

            this.gMapControl1.CacheLocation = System.Windows.Forms.Application.StartupPath;//缓存文件路径
            this.gMapControl1.MapProvider = GMapProviders.BingHybridMap;
            this.gMapControl1.Manager.Mode = AccessMode.ServerAndCache;//地图模式为本地缓存,完全离线

            this.gMapControl1.ShowCenter = true;//隐藏或显示中心十字
            this.gMapControl1.MinZoom = 1;
            this.gMapControl1.MaxZoom = 23;
            this.gMapControl1.Zoom = 12;
            //this.gMapControl.ShowTileGridLines = false;//道路网格线
            this.gMapControl1.DragButton = System.Windows.Forms.MouseButtons.Left;//左健拖动地图
            this.gMapControl1.MouseWheelZoomType = MouseWheelZoomType.MousePositionWithoutCenter;//不以中心点缩放
            this.gMapControl1.Position = new PointLatLng(34.2313041, 108.8774211);
        }

        #region IObjectSafety //以下 到 #endregion 为添加的代码,不需要做任何修改
        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";

        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);

        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;

        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            int Rslt = E_FAIL;

            string strGUID = riid.ToString("B");
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForScripting == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForInitializing == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            int Rslt = E_FAIL;
            string strGUID = riid.ToString("B");
            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                        Rslt = S_OK;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                        Rslt = S_OK;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }
        #endregion
       
    }


}

9. 在Release 模式下编译生成 ,,成功后就生成 就可以封闭组件啦

10,生成activex控件.....在当前解决方案里添加一新项目 Setup Project    没有的自行百度解决..网上资料很多

技术图片

添加工程后如下图,,在项目上  Add -- 项目输出     主输出   确定; 

技术图片

技术图片

 先点 下图的1 ,再点 2 的属性 ,,设置 3   Register为vsdrpCOM

技术图片

  

编译生成!!!!  这时在项目目录下就会 有setup 两个文件...这时控件就生成了,,安装就可以使用..可以直接双击setup1.msi安装..也可以在项目上右键 安装/卸载

 技术图片

安装结束后 在注册表里可查看是否安装成功

技术图片

 

 

 

以下是如何在QT中调用gMap

一.创建一个新的带窗口的QT工程

在pro 文件中添加配置   axcontainer ,  如下:   

QT       += core gui axcontainer

重新qmake 

添加头文件

#include <QAxWidget>

 

cpp中添加以下代码

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QAxWidget>  //activex控件头文件

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QAxWidget * axWidget = new QAxWidget(this);
    axWidget->setControl(QString::fromUtf8("{0E32CE01-4D40-45A6-8B59-B39ABFE8ADB0}"));//这里的guid 就是在gmap中生成添加的guid..同时在注册表中也可以看到
   // axWidget->resize(620,720);
    axWidget->show();
}

MainWindow::~MainWindow()
{
    delete ui;
}

 

 

正常来说到这里就可以使用了,,但我这次为了写这个记录,顺便操作了一次,不知道是什么原因没有成功调用...

哪天我发现了再上来说明

 

封装过程参考:https://www.cnblogs.com/wyynts/p/6874387.html

 

 

 

 

 

 

以上是关于将GMap封装为Activex供QT使用(工具:VS2017,QT5.12)的主要内容,如果未能解决你的问题,请参考以下文章

注册ActiveX控件

可以用 C# 构建一个 64 位 ActiveX 控件供企业应用程序使用吗

GMap.NET使用一

是否可以将ActiveX对象标记为安全,以便不需要更改IE设置?

使用C#开发ActiveX控件

Qt之zip压缩/解压缩(QuaZIP)