refactor: 水池截面中转文件改用 CoreTools::getTempFilePath #33

Merged
gjm merged 3 commits from company-desktop-computer/fix/pool-section-sat-name AGit into main 2026-10-22 10:09:15 +08:00
10 changed files with 176 additions and 36 deletions

No files matched your search

@@ -6189,3 +6189,45 @@ extern "C"
return pRegAll;
}
}
CString CoreTools::getTempFilePath(LPCTSTR pszFileMainName
, LPCTSTR pszFileSuffix
, LPCTSTR pszParentPath
, const bool & bUsePID
, const AcDbObjectId & objId)
{
CString sPath(_T("")), sTemp;
if (!pszFileMainName || !pszFileSuffix)
return sPath;
CString sParentPath(_T(""));
if (pszParentPath == NULL || _taccess(pszParentPath, 0x00) != 0x00)
sParentPath = FilePath::getSystemTemporaryFolder();
else
sParentPath = pszParentPath;
if (_taccess(sParentPath, 0x00) != 0x0)
return sPath;
CString sFileName(pszFileMainName);
if (bUsePID)
{
unsigned long pid = (unsigned long)::GetCurrentProcessId();
sTemp.Format(_T("%lu"), pid);
sFileName += sTemp;
}
if (objId.isValid())
{
sTemp.Format(_T("%I64u"), (unsigned __int64)objId.asOldId());
sFileName += sTemp;
}
sFileName += pszFileSuffix;
sPath = sParentPath + _T("\\") + sFileName;
return sPath;
}
@@ -129,11 +129,15 @@ bool FormatScriptFromSection(CString& sScr,STSection* pSection)
if (file.Open(sFullPath,CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt,(UINT)dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
sRegionScrp = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
sRegionScrp = CString(pszTxt, (int)nRead);
delete [] pszTxt;
file.Close();
@@ -2900,7 +2904,11 @@ bool AcDbX3dSolid::CreateFromSat(LPCTSTR pszSatFile,double dUnitScale)
//上一级目录
int nPos = sFullPath.ReverseFind(_T('\\'));
CString sPath = sFullPath.Mid(0,nPos + 1);
sFullPath = sPath + _T("temp\\temp.sat");
// 每次用唯一文件名:多个 CAD 实例同时从 SAT 重建时不会互相覆盖
static LONG s_nSatSeq = 0;
sFullPath.Format(_T("%stemp\\temp_%lu_%ld.sat"),(LPCTSTR)sPath
,(unsigned long)::GetCurrentProcessId(),(long)::InterlockedIncrement(&s_nSatSeq));
CFile file;
if (file.Open(sFullPath,CFile::modeCreate|CFile::modeWrite))
@@ -2912,6 +2920,8 @@ bool AcDbX3dSolid::CreateFromSat(LPCTSTR pszSatFile,double dUnitScale)
AcDbVoidPtrArray arPtr;
AcDbBody::acisIn(sFullPath,arPtr);
::DeleteFile(sFullPath);
//按照体积从大到小排序
Sort3dSolidByVol(arPtr);
@@ -580,11 +580,15 @@ CString GetSectionScr(AcDbRegion* pReg)
if (file.Open(sFullPath,CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt,(UINT)dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
sRegionScrp = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
sRegionScrp = CString(pszTxt, (int)nRead);
delete [] pszTxt;
file.Close();
+7 -3
View File
@@ -951,11 +951,15 @@ void CDGJMDlg::OnBnClickedBtaddtodb()
if (file.Open(sFullPath,CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt,dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
sRegionScrp = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
sRegionScrp = CString(pszTxt, (int)nRead);
delete [] pszTxt;
file.Close();
@@ -9418,11 +9418,15 @@ bool FormatScriptFromSection(CString& sScr,STSection* pSection)
if (file.Open(sFullPath,CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt,dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
sRegionScrp = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
sRegionScrp = CString(pszTxt, (int)nRead);
delete [] pszTxt;
file.Close();
+3 -6
View File
@@ -4,6 +4,7 @@
#include "JMSJDlg.h"
#include "GLTKDlg.h"
#include "KTSetting.h"
#include "CoreTools.h"
DLLIMPEXP CString IDCreate();
@@ -270,9 +271,7 @@ void CHZQTDlg::OnBnClickedCheck1()
CString sScr;
if (dlg.GetCrossSectionScr(sScr))
{
CString sFullPath = FilePath::GetSysDir();
sFullPath.MakeLower();
sFullPath += _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::GetSysDir());
CStdioFile file;
if (file.Open(sFullPath,CFile::modeCreate |CFile::modeWrite ))
@@ -394,9 +393,7 @@ void CHZQTDlg::SetFromWall(AcDbObjectId& id)
m_bUserDefSec = TRUE;
pWall->GetSpecialtyData(AcDb::kForRead)->GetAt(KEY_SECTIONSCR,m_sRegScr);
CString sFullPath = FilePath::GetSysDir();
sFullPath.MakeLower();
sFullPath += _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::GetSysDir());
CStdioFile file;
if (file.Open(sFullPath,CFile::modeCreate |CFile::modeWrite ))
+9 -7
View File
@@ -87,9 +87,7 @@ void CJMDBDlg::OnBnClickedButton1()
CString sScr;
if (dlg.GetCrossSectionScr(sScr))
{
CString sFullPath = FilePath::GetSysDir();
sFullPath.MakeLower();
sFullPath += _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::GetSysDir());
CStdioFile file;
if (file.Open(sFullPath,CFile::modeCreate |CFile::modeWrite ))
@@ -173,7 +171,7 @@ void CJMDBDlg::OnBnClickedButton2()
if (m_pSectionReg != NULL && bSuccess)
{
CString sFullPath = FilePath::getSystemTemporaryFolder() + _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::getSystemTemporaryFolder());
CString sRegionScrp = _T("");
CString sLine;
@@ -186,11 +184,15 @@ void CJMDBDlg::OnBnClickedButton2()
if (file.Open(sFullPath, CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt, dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
m_sRegScr = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
m_sRegScr = CString(pszTxt, (int)nRead);
DELETE_ARR_(pszTxt);
file.Close();
+10 -10
View File
@@ -78,9 +78,7 @@ BOOL CJMSJDlg::OnInitDialog()
void CJMSJDlg::ShowLastSection()
{
//1.截面
CString sFullPath = FilePath::getSystemTemporaryFolder();
sFullPath.MakeLower();
sFullPath += _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::getSystemTemporaryFolder());
AcDbVoidPtrArray arBodyPtrs;
if ( Acad::eOk == AcDbBody::acisIn(sFullPath,arBodyPtrs) )
@@ -139,7 +137,7 @@ void CJMSJDlg::OnBnClickedBtaddtodb()
UpdateData(TRUE);
if (!m_curSection.pReg) return;
CString sFullPath = FilePath::getSystemTemporaryFolder() + _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::getSystemTemporaryFolder());
CString sRegionScrp = _T("");
CString sLine;
@@ -152,11 +150,15 @@ void CJMSJDlg::OnBnClickedBtaddtodb()
if (file.Open(sFullPath, CFile::modeRead))
{
ULONGLONG dwFileLength = file.GetLength();
char* pszTxt = new char[dwFileLength];
int nLen = (int)dwFileLength;
file.Read(pszTxt, dwFileLength);
// 补终止符并按实际读到的长度赋值,避免把未初始化内存当字符串读
char* pszTxt = new char[nLen + 1];
::memset(pszTxt, 0, nLen + 1);
sRegionScrp = pszTxt;
UINT nRead = file.Read(pszTxt, nLen);
sRegionScrp = CString(pszTxt, (int)nRead);
DELETE_ARR_(pszTxt);
file.Close();
@@ -421,9 +423,7 @@ void CJMSJDlg::OnBnClickedBtselfromdb()
CString sScr,sScrT;
if (dlg.GetCrossSectionScr(sScr))
{
CString sFullPath = FilePath::getSystemTemporaryFolder();
sFullPath.MakeLower();
sFullPath += _T("\\JMSJ.sat");
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat"), FilePath::getSystemTemporaryFolder());
CStdioFile file;
if (file.Open(sFullPath,CFile::modeCreate |CFile::modeWrite ))
+13
View File
@@ -485,5 +485,18 @@ public:
// arInput 里面的曲线必须是同一平面内的,没有悬空边线
// 并且确实组成了一个或者多个闭合的轮廓
static AcDbPolyline* getOuterContour(const AcDbVoidPtrArray &arInput);
// 获得一个临时文件路径
// pszFileMainName 是文件名称的主体部分,不包含后缀名, 在后面根据 bUsePID 决定是否加上进程号
// pszFileSuffix 是文件后缀名, 例如 ".txt" 或者 ".jpg"
// pszParentPath 是文件所在的父目录,如果为空,则使用系统临时目录
// bUsePID 是否在文件名中加入进程号,避免同名冲突
// objId 是实体id,如果不为空,则在文件名中加入实体id,避免同名冲突
static CString getTempFilePath(LPCTSTR pszFileMainName
, LPCTSTR pszFileSuffix
, LPCTSTR pszParentPath = NULL
, const bool &bUsePID = true
, const AcDbObjectId &objId = AcDbObjectId::kNull
);
};
+64
View File
@@ -0,0 +1,64 @@
# 临时文件命名与多实例安全
> 记录全库临时文件(ACIS SAT、DWG 中转等)的命名规则、现状与遗留项。
> 最后更新:2026-10-22
## 规则
1. 文件名必须带 `GetCurrentProcessId()`,直接用 `CoreTools::getTempFilePath()` 生成。同一进程内需要多次独立使用、彼此不能共享的,再加原子递增序号。
2. 用完即删(`::DeleteFile`)。写读双方跨函数隐式传递的文件除外,见下文 `JMSJ.sat`。
3. 路径统一用 `FilePath::getSystemTemporaryFolder()`,不要落到安装目录。
4. 从 DWG 里读回来的文件名不可信,必须只取纯文件名,拒绝 `..\`、盘符等路径成分。
5. 从文件读进缓冲区再当字符串用时:分配 `nLen + 1`、清零,按 `Read` 实际返回的长度构造 `CString`,不要直接 `CString = pszTxt`。
## 现状
| 位置 | 改前 | 改后 | 状态 |
| --- | --- | --- | --- |
| `CoreCommand/CoreTools.cpp` `MakeTempSatPath` | — | `x3d_<pid>_<seq>.sat` | 已符合,调用方负责删除 |
| `CoreLibrary/AcDbX3dSolid.cpp` `CreateFromSat` | `temp\temp.sat` | `temp_<pid>_<seq>.sat` | 已修,用完删除 |
| `CoreLibrary/AecDbEwPipeBase.cpp` `RegionAcisoutDwgOutFields` | `Region_<handle>.dat` | `Region_<pid>_<tag>.dat` | 已修;未入库实体无句柄时用序号 `N<n>` |
| `Pool3dCmd/JMDBDlg.cpp` `JMSJDlg.cpp` `HZQTDlg.cpp` | `JMSJ.sat` | `JMSJ_<pid>.sat` | 已修,见下文 |
| `CoreCommand/KTEarthWormCmd.cpp` `CO_RGCSCmdFnc` | `Region_<handle>.dat` | 未改 | 测试命令,不在产品链路,暂不处理 |
| `DGJM.sat` 20 处 | `DGJM.sat` | 未改 | 代码已废弃,见下文 |
| `PipelineCmd` `temp_$_$_.equ`、`tmp_dwg_$$%d.dwg` | 固定名 | 未改 | 界面导出路径,多实例会冲突,低优先级 |
## DGJM.sat:废弃代码,不再处理
分布:`AcDbX3dSolid.cpp`(2)、`AecDbEarthWormFitting.cpp`(2)、`AcDbX3dGroup.cpp`(3)、`EarthWormCmd/*`(13)。
这是写方 `acisOut` 和读方 `acisIn` 之间的隐式约定:A 函数把 region 写到固定文件,B 函数再从同一个文件读回来。加 PID 或序号会让读方找不到文件,必须先把接口改成「写方返回路径、读方接收路径」才能动。
该链路已整体废弃,**文件名保持原样,不再改造**。只在 PR #31 中修了读取越界:`new char[n]` 后直接赋给 `CString` 会把堆里的随机字节当字符串读,现改为 `new char[n+1]` + 清零 + 按实际长度构造。涉及 `AcDbX3dSolid`、`AecDbEarthWormFitting`、`DGJMDlg`、`GJYXJMDlg`、`JMDBDlg`、`JMSJDlg` 共 6 处。
若将来这段代码被复用,先改接口,再按本文规则命名。
## JMSJ.sat:水池截面中转
7 处,分布在 3 个文件:
| 文件 | 用途 |
| --- | --- |
| `JMDBDlg.cpp` | 从标准库选截面(写)→ `acisIn`;`acisOut` 导出截面字符串(读) |
| `JMSJDlg.cpp` | `ShowLastSection` 读上次截面;入库时 `acisOut` 导出;从标准库选截面(写)→ `acisIn` |
| `HZQTDlg.cpp` | 从标准库选截面(写)→ `acisIn`,两处 |
目录原本分两套:`JMDBDlg` / `JMSJDlg` 用 `FilePath::getSystemTemporaryFolder()`,`HZQTDlg` 用 `FilePath::GetSysDir()`(安装目录下的 `sys`)。两套互不相干,本次只加 PID 后缀,目录未动。
统一走 `CoreTools::getTempFilePath()`(`CoreCommand/CoreTools.cpp`):
```cpp
CString sFullPath = CoreTools::getTempFilePath(_T("JMSJ_"), _T(".sat")
, FilePath::getSystemTemporaryFolder());
// -> <temp>\JMSJ_<pid>.sat
```
`getTempFilePath` 是通用工具:主名 + 可选进程号 + 可选实体 id + 后缀;父目录为空或不存在时落到系统临时目录。
同一进程内所有调用点返回同一路径,所以 `acisOut` 写完、`ShowLastSection` 再读这条隐式链路仍然成立;进程之间用 PID 隔离,两个 CAD 实例不会再互相覆盖。
**已知取舍**:`CJMSJDlg::ShowLastSection` 在 `OnInitDialog` 里读这个文件,只用于对话框打开时显示上一个设计好的截面,不是功能数据。加 PID 后新进程读不到上个进程留下的截面,已确认可接受。
## 待处理
- `PipelineCmd` 的 `temp_$_$_.equ`、`tmp_dwg_$$%d.dwg`:界面导出路径,多实例会冲突,暂未改。