I have a need to rename files from outside SOLIDWORKS that are open inside SOLIDWORKS. The PDM API has a handy ForceReleaseLocks method that is supposed to detach a file from the file system so that it can be modified and such. I’ve found that this doesn’t seem to work for out-of-process code. To test this, I have a part file named ‘A.SLDPRT’ in my PDM vault and I open it in SOLIDWORKS:
The file is checked in, but is in a state and folder where I do have rename permissions.
I can write a macro like this:
Dim swApp As SldWorks.SldWorks
Dim v As EdmVault5
Dim f As IEdmFile18
Dim pFolder As IEdmFolder13
Dim retval As Integer
Dim nextDoc As ModelDoc2
Dim mExt As ModelDocExtension
Dim vDocs As Variant
Dim newPath As String
Sub main()
Set swApp = Application.SldWorks
Set v = New EdmVault5
v.LoginAuto "_DEVELOPMENT", 0
vDocs = swApp.GetDocuments()
For i = LBound(vDocs) To UBound(vDocs)
Set nextDoc = vDocs(i)
If nextDoc.GetTitle = "A.sldprt" Then
retval = nextDoc.ForceReleaseLocks()
Set f = v.GetFileFromPath(nextDoc.GetPathName(), pFolder)
f.RenameEx 0, "X" & nextDoc.GetTitle(), 0
Set mExt = nextDoc.Extension
newPath = f.GetLocalPath(pFolder.ID)
retval = mExt.ReloadOrReplace(True, newPath, True, True)
If retval <> swComponentReloadError_e.swReloadOkay Then
retval = swApp.SendMsgToUser2("Error reloading", swMessageBoxIcon_e.swMbStop, swMessageBoxBtn_e.swMbOk)
End If
Exit Sub
End If
Next i
End Sub
and it works without problems. The file is renamed to XA.SLDPRT and the feature tree reflects this change:
If I write a console application to do the same thing:
using EPDM.Interop.epdm;
using System.Runtime.InteropServices;
using SolidWorks.Interop.sldworks;
using SolidWorks.Interop.swconst;
namespace ConsoleApp1
{
class RenameExTest
{
private static IEdmVault22 vault;
private const string VAULT_NAME = "_DEVELOPMENT";
private static SldWorks swApp;
private static int windHandle = 0;
static void Main(string[] args)
{
vault = new EdmVault5() as IEdmVault22;
windHandle = (int)System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
vault.LoginAuto(VAULT_NAME, windHandle);
swApp = Marshal.GetActiveObject("SldWorks.Application") as SldWorks;
object[] openDocsObjArray = swApp.GetDocuments() as object[];
foreach (object obj in openDocsObjArray)
{
ModelDoc2 nextDoc = obj as ModelDoc2;
if (nextDoc.GetTitle().Equals("A.sldprt")) {
nextDoc.ForceReleaseLocks();
IEdmFolder5 pFolder;
IEdmFile18 f = vault.GetFileFromPath(nextDoc.GetPathName(), out pFolder) as IEdmFile18;
string newName = "X" + nextDoc.GetTitle();
f.RenameEx(windHandle, newName, 0);
string newPath = f.GetLocalPath(pFolder.ID);
ModelDocExtension mExt = nextDoc.Extension;
int retval = mExt.ReloadOrReplace(false, newPath, true, false);
if (retval != (int)swComponentReloadError_e.swReloadOkay) {
retval = swApp.SendMsgToUser2("Error reloading", (int)swMessageBoxIcon_e.swMbStop, (int)swMessageBoxBtn_e.swMbOk);
}
}
}
}
}
}
the program errors out with a rather cryptic PDM exception:
and strangely the file actually does get renamed in the vault, but SW doesn’t update. Also, if I wrap that RenameEx call in a try block and ignore the exception, I can inspect the Name property of the f variable and it still shows the old name, even though the file in the vault is renamed:
The subsequent attempt to call to ReloadOrReplace
then fails because the call to GetLocalPath
returns a file with the name A.SLDPRT but the file has been renamed XA.SLDPRT.
To add even more confusion, if I run the program when the only file open in SOLIDWORKS is an assembly that contains A.SLDPRT, the RenameEx
call fails, but with a different error code:
This error sort of makes sense, but I thought that ForceReleaseLocks would prevent it. Ignoring the exception leads to ReloadOrReplace failing with a different error, stating that the document hasn’t changed.
All in all, a giant confusing mess.
Has anyone used these methods successfully in an out of process scenario? My particular use case will be doing stuff like this from a PDM add-in (which run outside the SW process) which fails in the same manner.