Create Documents using SDK

Hi guys,

I want to, whenever a user click in a option created in PW and select a File from a FileDialog, this file should be created in PW. The first step of it (Create menu option and FileDialog) was acomplished succesfully. Now, i'm having problems to create the selected file as a document in PW. I tried what is described in this link http://communities.bentley.com/products/projectwise/projectwise_programming/f/342995/t/56503.aspx, but with no success. Could someone help me? Here is the code that i'm trying to create the document in PW (It's in C++ using MFC):

LONG docID = lpDocItem->lDocumentId;
LONG projectID = lpDocItem->lProjectId;

LONG *lngDocID;
*lngDocID = 0;

LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(projectID, 0);

LPWSTR strWorkingDir = L" ";
BOOL status = aaApi_CreateDocument(lngDocID, projectID, 0, AADMS_FTYPE_UNKNOWN ,
AADMS_ITYPE, lngAppID, 1, lngWorkSpaceID, FileDlg.GetPathName(),
FileDlg.GetFileName(), FileDlg.GetFileName(), NULL, NULL,
false, AADMSDOCCREF_DEFAULT, strWorkingDir,
512, 0);
Parents
  • Something like this might work:

    LONG docID = 0L;
    LONG projectID = lpDocItem->lProjectId; // not sure where you are getting this, but as long as it is a valid value...
    LONG lAttributeId = 0;
    LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
    LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(projectID, 0);
    WCHAR strWorkingDir[_MAX_PATH];   // for checked out file location
    memset (strWorkingDir, '\0', _MAX_PATH);BOOL status = aaApi_CreateDocument(
                      &docID,   // new document's doc id
                      projectID,   // id of folder to create doc in
                      0,    // 0 means default storage
                      0,    // 0 unless you have reason to use something else
                      0,    // 0 unless you have reason to use something else
                      lngAppID,   // 0 means none for application
                      0,    // 0 means none for department
                      lngWorkSpaceID,  // workspace profile
                      FileDlg.GetPathName(), // source file
                      FileDlg.GetFileName(), // what to call the file in PW
                      FileDlg.GetFileName(), // doc name
                      NULL,    // doc description
                      NULL,    // version string - you might want to check DS settings...
                      FALSE,   // TRUE means file is checked out at create time
                      AADMSDOCCREF_DEFAULT,  // check documentation for ulFlags
                      strWorkingDir,  // location of the file if checked out
                      _MAX_PATH - 1,  // make sure the buffer is large enough
                      &lAttributeId   // new attribute id in environment if created - see ulFlags
                      );

     

Reply
  • Something like this might work:

    LONG docID = 0L;
    LONG projectID = lpDocItem->lProjectId; // not sure where you are getting this, but as long as it is a valid value...
    LONG lAttributeId = 0;
    LONG lngAppID = aaApi_GetFExtensionApplication(L"pdf");
    LONG lngWorkSpaceID = aaApi_GetWorkspaceProfileId(projectID, 0);
    WCHAR strWorkingDir[_MAX_PATH];   // for checked out file location
    memset (strWorkingDir, '\0', _MAX_PATH);BOOL status = aaApi_CreateDocument(
                      &docID,   // new document's doc id
                      projectID,   // id of folder to create doc in
                      0,    // 0 means default storage
                      0,    // 0 unless you have reason to use something else
                      0,    // 0 unless you have reason to use something else
                      lngAppID,   // 0 means none for application
                      0,    // 0 means none for department
                      lngWorkSpaceID,  // workspace profile
                      FileDlg.GetPathName(), // source file
                      FileDlg.GetFileName(), // what to call the file in PW
                      FileDlg.GetFileName(), // doc name
                      NULL,    // doc description
                      NULL,    // version string - you might want to check DS settings...
                      FALSE,   // TRUE means file is checked out at create time
                      AADMSDOCCREF_DEFAULT,  // check documentation for ulFlags
                      strWorkingDir,  // location of the file if checked out
                      _MAX_PATH - 1,  // make sure the buffer is large enough
                      &lAttributeId   // new attribute id in environment if created - see ulFlags
                      );

     

Children
  • Dan, I tried using something similar to your code to upload a file to ProjectWise, but I keep getting error 50132: "The file does not exist."

    My code is basically the same, except I replaced the FileDlg calls with a function to convert CHAR* to LPCWSTR, because I'm not building a MFC app, this is just a DLL ultimately for use in VBA:

    LPCWSTR convertCharArrayToLPCWSTR(char* charArray)
    {
     std::string charStr=std::string(charArray);
     std::wstring sTemp=std::wstring(charStr.begin(),charStr.end());
     LPCWSTR funcArg=sTemp.c_str();
     return funcArg;
    }

    bool __stdcall FileOperator::uploadDocument(char* filePath,long projectID)
    {
     char* filename="xyz.xlsx";
     char* docname="xyz.xlsx";
     long docID=0L;
     long lAttributeID=0;
     long lngAppID=aaApi_GetFExtensionApplication(L"xlsx");
     long lngWorkSpaceID=aaApi_GetWorkspaceProfileId(projectID,0);
     WCHAR strWorkingDir[_MAX_PATH];

     memset(strWorkingDir,'\0',_MAX_PATH);

     bool status=aaApi_CreateDocument(
    &docID,
    projectID,
    0,
    0,
    0,
    lngAppID,
    0,
    lngWorkSpaceID,
    convertCharArrayToLPCWSTR(filePath),
    convertCharArrayToLPCWSTR(filename),
    convertCharArrayToLPCWSTR(docname),
    NULL,
    NULL,
    FALSE,
    AADMSDOCCREF_DEFAULT,
    strWorkingDir,
    _MAX_PATH-1,
    &lAttributeID
      );
      long errorID=aaApi_GetLastErrorId();
      LPCWSTR errorStr=aaApi_GetLastErrorDetail();
      return status;
    }

    Here's the console app that I used to call the code:

    #include "stdafx.h"
    #include <iostream>
    #include "../myProject/myProject.h"

    using namespace std;

    int main()
    {
     long initResult=myProject::FileOperator::initialize(abc.def.com:PWOPPID_xyz");
     bool uploadResult=myProject::FileOperator::uploadDocument("u:\Software Development\\abc\\def\\ghi\xyz.xlsx",1799);
     return 0;
    }

    I know that the file exists at this path; that's a direct copy/paste of the path given in the file properties.  Why is aaApi_CreateDocument() unable to find it?

    Sorry if this is a thread hijack, I can repost if needed, but it seemed closely related enough.

  • Maybe Dan can provide more input since I don't want to interfere with the current communication.

    If you have not, you may want to consider using the Microsoft Visual Studio debugger to closely examine all function parameters as being 100% correct to a "failing function call" prior to the call of that function.  Microsoft makes it very easy to place break points and "fly over" a parameter to see what the value is when it is frozen in time before a call that is failing.

    If the sample code you posted was copied and pasted directly (encouraged) and was not a simply typo in the posting process, then the line in main() for the file name is not fully escaping all backslash characters with double backslashes as required for any string literals.  Make sure to double backslash any single backslashes like: "u:\" and "\xyz.xlsx".

    HTH,

    Bob



  • Joshua,

    A few things come to mind.

    1) I think Bob is correct in that your hard coded path isn't correct; it has some single backslash characters.

    2) I'm not convinced that you are accounting for the differences between ANSCII and UNICODE in your code.

    3) I'm suspicious of your convertCharArrayToLPCWSTR() function. You allocate a variable for a new string that you return a pointer to, but won' that go away after you return from the function? Shouldn't it be static? It may work because of how quickly you use it, but it seems to me that you are returning a pointer to something that isn't guaranteed to be there after you exit the function.

    Here's what I suggest:

    1) Create your DLL with C/C++ and the PW SDK.

    2) Create a test program to fully test your DLL, but create that test program with C/C++.

    3) Once you are convinced that your DLL works as designed with C/C++, then try to make it work with VBA.

     

  • Thanks for catching the non-escaped slash. I changed the file path so that all the slashes are escaped as double backslashes.  I also changed the file path to a UNC path.

    Yes, it looks like the problem might be with convertCharArrayToLPCWSTR().  After this line is executed:

    LPCWSTR funcArg=sTemp.c_str();

    then funcArg has the correct value.  But then, after this line is executed:

    return funcArg;

    then funcArg has become garbage data.

    I'm having a lot of trouble figuring out how to convert a string to an LPCWSTR, which is used throughout the ProjectWise API.  It seems that if I want to cast it using, e.g.

    LPCWSTR xyz=(LPCWSTR)myInputString

    then I have to switch from Unicode to multi-byte, but if I do that the API throws an error because:

    #if !defined(UNICODE) && !defined(NOUNICODE)
    #error UNICODE is not defined. UNICODE must be defined for correct API arguments.
    #endif

    What's the best way to convert from char* to LPCWSTR?



  • I got it working.

    Here's the conversion to LPCWSTR I'm using:

    wchar_t *convertCharArrayToLPCWSTR(const char* charArray)
    {
    wchar_t* wString=new wchar_t[4096];
    MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
    return wString;
    }