TDropBoxItem C++ issue

I need to create a couple of folders in dropbox and then upload a
file. I'm using C++ Builder XE4 on Windows 7 64-bit. I created a small test
program. I'm able to create the folders correctly, but I can't see how
to properly convert a TCloudItem (which is the result I get after
creating the folder(s)), into a TDropBoxItem for use with the Upload
function which requires a TDropBoxItem (Not a TCloudItem like the
documentation says). The constructor requires a TCollection pointer, so
I'm at a loss, and all their examples are all in Pascal. Here's the code I'm working with:

TCloudItem *CompanyFolder = AdvDropBox1->CreateFolder(NULL, "01"); // Root level
TCloudItem *TechFolder = AdvDropBox1->CreateFolder(CompanyFolder, "TechID");
TDropBoxItem *Folder = new TDropBoxItem(???????); // How do I take TechFolder and "pass" it here?
TDropBoxItem *WorkOrderIn = AdvDropBox1->Upload(Folder, "C:\Users\Public\Documents\test.in");

For something so simple, this has proved very frustrating.

Hi,


TDropBoxItem descends from TCloudItem so you can cast the folder object.

This is demonstrated in the CloudStorageDemo (included with the product download).

Example:

var
  dif: TDropBoxItem;
  ci: TCloudItem;
begin
  dif := nil;

    if Assigned(TreeView1.Selected) then
    begin
      ci := TCloudItem(TreeView1.Selected.Data);
      if ci.ItemType = ciFolder then
      begin
        dif := ci as TDropBoxItem;
      end;
    end;

The example you provide is in Pascal which handles things very differently than C++.

I've tried both static and dynamic casts of the TCloudItem pointer to a TDropBoxItem pointer and both fail to provide a proper TDropBoxItem for use with the Upload function. The Upload function doesn't create the file in the right location, and then crashes in both cases. (This isn't surprising since we're trying to cast a smaller object (TCloudItem) to a larger object (TDropBoxItem), which creates memory problems. If it were the other way around there wouldn't be an issue since the extra items in TDropBoxItem would simply get dropped. In other words TDropBoxItem knows everything about TCloudItem, but TCloudItem doesn't know everything about TDropBoxItem, and thus can't properly instantiate it.)

You should NOT create a new TDropBoxItem. AdvDropBox->CreateFolder does return a TDropBoxItem already.

Did you try:

TCloudItem *CompanyFolder = AdvDropBox1->CreateFolder(NULL, "01"); // Root level
TCloudItem *TechFolder = AdvDropBox1->CreateFolder(CompanyFolder, "TechID");
TDropBoxItem *Folder = reinterpret_cast<TDropBoxItem>TechFolder;
TDropBoxItem *WorkOrderIn = AdvDropBox1->Upload(Folder, "C:\\Users\\Public\\Documents\\test.in");

First of all the proper code line is:

TDropBoxItem Folder = reinterpret_cast<TDropBoxItem>(TechFolder);

Secondly (and perhaps I have a different version of the code) CreateFolder doesn't give any indication that it's returning a TDropBoxItem . In CloudDropBox.hpp in the TAdvDropBox class declaration, the CreateFolder reads as follows:

virtual Cloudbase::TCloudItem
__fastcall CreateFolder(Cloudbase::TCloudItem* ci, const System::UnicodeString FolderName);

It also shows up in the IDE as returning a TCloudItem pointer.

Regardless using the approach above works except that the Upload function crashes with the following error. (After apparently uploading the file successfully, since I can see it in my dropbox
in the correct location, and can confirm it is a proper copy of the file
when I download it.)

---------------------------
Dropboxtest
---------------------------
Access violation at address 50154A58 in module 'rtl180.bpl'. Read of address 00000004.
---------------------------
OK  
---------------------------

This appears to be a bug since using the following code, generates the same crash after calling Upload:

TDropBoxItem *Test = NULL;
Test = AdvDropBox1->GetFolderInfo("01"); // Folder absolutely exists already
TDropBoxItem *WorkOrderIn = AdvDropBox1->Upload(Test, "C:\Users\Public\Documents\test.in");

Furthermore assuming you're right that AdvDropBox->CreateFolder returns a TDropBoxItem pointer, then the pointer casting wouldn't even be necessary, and the following code would work instead:

TCloudItem *CompanyFolder = AdvDropBox1->CreateFolder(NULL, "01"); // Root level
TDropBoxItem *TechFolder = AdvDropBox1->CreateFolder(CompanyFolder, "TechID");
TDropBoxItem *WorkOrderIn = AdvDropBox1->Upload(TechFolder, "C:\Users\Public\Documents\test.in");

However, the above won't even compile with the error: [C++ Error] CPTest2.cpp(30, 79): E2034 Cannot convert 'TCloudItem *' to 'TDropBoxItem *'

From a strictly C++ viewpoint there should be a TDropBoxItem class constructor that takes a TCloudItem pointer as it's argument. Then it could copy over the relevant information from the base class, as well as properly initialize the class values unique to TDropBoxItem.

Also since you are creating new instances of your classes dynamically and returning pointers to them, I assume I can use delete on such pointers when I am finished using them to clean up memory without problems, correct?
  1. I told you AdvDropBox-CreateFolder DOES create an instance of TDropBoxItem.
    2) Yes, the base class definition is that it returns TCloudItem. TDropBoxItem descends from TCloudItem. Each cloud storage component descends from the same base class but returns its own descending class from TCloudItem.
    3) In your code you are still not casting the CreateFolder result to TDropBoxItem:
    TDropBoxItem *TechFolder = AdvDropBox1->CreateFolder(CompanyFolder, "TechID");
    4) The result object of CreateFolder is maintained in the CloudStorage drive information collection and is destroyed from the cloud storage component itself.

Since CreateFolder returns a TDropBoxItem instead of a TCloudItem can you explain why the following code doesn't result in equivalent TDropBoxItem pointers?

TCloudItem *CompanyFolder = AdvDropBox1->CreateFolder(NULL, "01"); // Root level
TDropBoxItem FolderTest = reinterpret_cast<TDropBoxItem>(CompanyFolder);
TDropBoxItem *FolderMaster = AdvDropBox1->GetFolderInfo("01");

Specifically FRevision, FModifiedDate, and FCollection are different between FolderTest and FolderMaster above (otherwise they appear to be the same).

Also if the first argument to the Upload function is intended to specify a location for the file (with NULL representing the root directory) why is a TDropBoxItem even necessary?

The Upload function crashes every time if I provide a TDropBoxItem pointer representing a folder location in the first argument (regardless of how I get that TDropBoxItem pointer, see above). Only if I provide NULL for the first argument does it work normally without a crash.

To be sure, can you retest with v2.4.11.0?



Yes I'll be happy to. However since we haven't yet purchased the cloudpack for VCL, has the demo version been updated as well?

It was updated as you can see at: http://www.tmssoftware.com/site/cloudpack.asp



Are you sure the demo was updated? Because I uninstalled the old version. Restarted my machine. Downloaded new version (with same file name as old one BTW), and ran the installer. The AdvDropBox1 control I drop on the form shows Version 1.3.1.1 in the properties window, and it's not working right either. (Appears to fail at call GetFolderInfo, which returns a badly formed TDropBoxItem.)

The installer is dated Apr 10, 2014 and the installer should show version v2.4.11.0



OK, I must have downloaded too fast, since I had version 2.4.10. Uninstalled that version, and downloaded the latest and confirmed that it is 2.4.11. Opened my test project and did a clean and build and then proceeded to test it. Unfortunately it seems to have a new problem. Since I first started this thread, my test code has evolved somewhat. Here's what I'm using now:


bAuthorized = false;
    AdvDropBox1->DoAuth();
    if(bAuthorized)
    {
        TCloudItem *CompanyFolder = NULL;
        TDropBoxItem *FolderTest = NULL;
        FolderTest = AdvDropBox1->GetFolderInfo("01");
        if(FolderTest == NULL)
            CompanyFolder = AdvDropBox1->CreateFolder(NULL, "01"); // Root level   // With latest "Demo" version this appears to return a malformed TDropBoxItem and...
        else
            CompanyFolder = FolderTest;
        FolderTest = NULL;
        FolderTest = AdvDropBox1->GetFolderInfo("01/TECH");
        if(FolderTest == NULL)
        {
            AdvDropBox1->CreateFolder(CompanyFolder, "TECH"); // ... crashes this function
            FolderTest = AdvDropBox1->GetFolderInfo("01/TECH");
        }
        TDropBoxItem *WorkOrderIn = AdvDropBox1->Upload(FolderTest, "C:\\Users\\Public\\Documents\\001001.in");
    }



The CreateFolder() function doesn't create the "01" folder I asked it to, and what it returns doesn't appear to be a valid TCloudItem, as you can see in this image from the debugger:



As a result the call to the next CreateFolder() which tries to use the CompanyFolder variable crashes the program.

I retested this here in C++ and I could not see a single problem.

Test code to create new folder & upload a file to it:


void __fastcall TForm5::Button2Click(TObject *Sender)
{
  TDropBoxItem *di;
  TDropBoxItem *upload;

  di = (TDropBoxItem *) AdvDropBox1->CreateFolder(NULL, "test");

  Caption = di->FileName;

  upload = (TDropBoxItem *) AdvDropBox1->Upload(di, "C:\temp\000kun.csv");
}

I was finally able to get the fully licensed version of your CloudPack for VCL and using this same code:


The folder functions now work correctly, but the upload function absolutely does not. I found another Upload() function that DOES work that simply takes a string such as "01/TECH" as it's first argument and the location of the file to upload as it's second and that works without errors. But that function isn't documented anywhere.