创建SOLIDWORKS C++独立应用程序:开发实战

在本教程中,我将演示如何使用C++和Microsoft Visual Studio从进程外(也称为独立)应用程序(例如MFC,Win32控制台应用程序)连接到SOLIDWORKS应用程序。

有关本文中讨论的方法的更详细说明,请参阅《如何使用SOLIDWORKS API创建独立(exe)应用程序》一文。

创建新项目

我将使用Microsoft Visual Studio开发环境。您可以使用任何版本的 Visual Studio。相同的代码适用于专业版、精简版或社区版。

  • 打开Visual Studio。
  • 启动新项目:

在 Visual Studio 中创建新项目

  • 选择项目模板。我建议从 Win32 控制台应用程序项目模板开始,因为它包含最少的预生成代码:

选择 Win32 控制台应用程序C++项目模板

  • 勾选项目向导中的 ATL 选项:

Win32 控制台应用程序模板设置

链接SOLIDWORKS 类型库所在的目录。这是 SOLIDWORKS 的安装目录(转到项目属性,选择 C/C++ 并浏览其他包含目录字段中的路径):

项目中C++其他“包含目录”选项

现在我们可以添加代码以连接到 SOLIDWORKS 实例。

创建或连接到实例

连接到 COM 服务器的最常见和最快速的方法可能是使用 CoCreateInstance 函数。(https://learn.microsoft.com/zh-cn/windows/win32/api/combaseapi/nf-combaseapi-cocreateinstance)

#include "stdafx.h"
#import "sldworks.tlb"
#include <iostream>

int main()
{
    ::CoInitialize(NULL);
    CComPtr<SldWorks::ISldWorks> pSwApp;

    if (SUCCEEDED(pSwApp.CoCreateInstance(
        __uuidof(SldWorks::SldWorks), NULL, CLSCTX_LOCAL_SERVER)))
    {
        pSwApp->Visible = TRUE;
        _bstr_t revNmb = pSwApp->RevisionNumber();

        std::cout << revNmb;
    }

    pSwApp = NULL;
    ::CoUninitialize();

    //wait for input (do not close console to see results)
    std::cin.get();

    return 0;
}

通过 ROT 获取正在运行的实例

为了连接到已经运行的特定 SOLIDWORKS 会话或能够创建多个会话,您可以使用正在运行的对象表 API。请阅读《如何使用SOLIDWORKS API创建独立(exe)应用程序》一文,了解有关此方法的更多详细信息。

#include "stdafx.h"
#import "sldworks.tlb"
#include <iostream>
#include <windows.h>
#include <string>
#include <chrono>
#include <thread>

HRESULT StartSwProcess(LPCWSTR appPath, int& prcId)
{
    prcId = -1;

    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory(&si, sizeof(si));

    HRESULT res = E_FAIL;

    if(CreateProcess(L"C:\\Program Files\\SOLIDWORKS Corp\\SOLIDWORKS\\SLDWORKS.exe",
        L"", NULL, NULL, FALSE, 0,
        NULL, NULL, &si, &pi))
    {
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        prcId = pi.dwProcessId;

        res = S_OK;
    }

    return res;
}

HRESULT GetSwAppFromProcess(int prcId, SldWorks::ISldWorks** pSwApp)
{
    HRESULT res = E_FAIL;

    CComPtr<IRunningObjectTable> pRot;
    CComPtr<IBindCtx> pBindingContext;

    if (SUCCEEDED(CreateBindCtx(0, &pBindingContext)))
    {
        if (GetRunningObjectTable(0, &pRot) == S_OK)
        {
            CComPtr<IEnumMoniker> pEnumMoniker;
            if (SUCCEEDED(pRot->EnumRunning(&pEnumMoniker)))
            {
                WCHAR szMonikerName[30];
                swprintf_s(szMonikerName, 30, L"SolidWorks_PID_%d", prcId);

                ULONG fetched;
                CComPtr<IMoniker> pMon;

                while (pEnumMoniker->Next(1, &pMon, &fetched) == S_OK)
                {
                    LPOLESTR pName;
                    pMon->GetDisplayName(pBindingContext, NULL, &pName);

                    if (wcscmp(pName, szMonikerName) == 0)
                    {
                        CComPtr<IUnknown> pUnk;

                        if (SUCCEEDED(pRot->GetObjectW(pMon, &pUnk)))
                        {
                            if (SUCCEEDED(pUnk->QueryInterface(_uuidof(SldWorks::ISldWorks), (void**)pSwApp)))
                            {
                                res = S_OK;
                                break;
                            }
                        }
                    }

                    pMon = NULL;
                }
            }
        }
    }

    pRot = NULL;
    pBindingContext = NULL;

    return res;
}

HRESULT ConnectToSwApp(LPCWSTR appPath, SldWorks::ISldWorks** pSwApp, int timeoutSec)
{
    HRESULT res = E_FAIL;

    int prcId;

    if (SUCCEEDED(StartSwProcess(appPath, prcId)))
    {
        auto start = std::chrono::high_resolution_clock::now();

        while (FAILED(GetSwAppFromProcess(prcId, pSwApp)))
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
            auto end = std::chrono::high_resolution_clock::now();
            std::chrono::duration<double, std::milli> elapsed = end - start;

            if (elapsed.count() > timeoutSec * 1000)
            {
                throw std::runtime_error("Timeout");
            }
        }

        res = S_OK;
    }

    return res;
}

int main()
{
    ::CoInitialize(NULL);

    CComPtr<SldWorks::ISldWorks> pSwApp;

    try
    {
        if (SUCCEEDED(ConnectToSwApp(L"C:\\Program Files\\SOLIDWORKS Corp\\SOLIDWORKS (2)\\SLDWORKS.exe",
            &pSwApp, 10)))
        {
            _bstr_t revNmb = pSwApp->RevisionNumber();
            std::cout << revNmb;
        }
    }
    catch (std::runtime_error& e)
    {
        std::cout << e.what() << std::endl;
    }

    pSwApp = NULL;

    ::CoUninitialize();

    //wait for input (do not close console to see results)
    std::cin.get();

    return 0;
}

在上面的示例中,通过从SOLIDWORKS应用程序安装路径启动新进程来启动SOLIDWORKS的新会话。ConnectToSwApp 函数需要 sldworks.exe 的完整路径作为第一个参数,timeout(超时,以秒为单位)作为第二个参数。超时将确保在进程无法启动的情况下应用程序不会被锁定。

文章翻译自https://www.codestack.net/

仅供学习使用。

QR Code
微信扫一扫,欢迎咨询~

联系我们
武汉格发信息技术有限公司
湖北省武汉市经开区科技园西路6号103孵化器
电话:155-2731-8020 座机:027-59821821
邮件:tanzw@gofarlic.com
Copyright © 2023 Gofarsoft Co.,Ltd. 保留所有权利
遇到许可问题?该如何解决!?
评估许可证实际采购量? 
不清楚软件许可证使用数据? 
收到软件厂商律师函!?  
想要少购买点许可证,节省费用? 
收到软件厂商侵权通告!?  
有正版license,但许可证不够用,需要新购? 
联系方式 155-2731-8020
预留信息,一起解决您的问题
* 姓名:
* 手机:

* 公司名称:

姓名不为空

手机不正确

公司不为空