@@ -1599,6 +1599,69 @@ HRESULT nsDataObj::GetFile(FORMATETC& aFE, STGMEDIUM& aSTG) {
1599
1599
return E_FAIL;
1600
1600
}
1601
1601
1602
+ static HRESULT AssignDropfile (STGMEDIUM& aSTG, nsAString const & aPath) {
1603
+ // Struct describing the data in the OLE memory space. Marginally cleaner than
1604
+ // completely-manual pointer manipulation.
1605
+ struct DFWithPaths {
1606
+ DROPFILES dropfiles;
1607
+ // An epsilon-terminated list of NUL-terminated strings.
1608
+ // See the CF_HDROP shell clipboard format for more info.
1609
+ WCHAR paths[];
1610
+ };
1611
+
1612
+ // C++ doesn't have a dependent-type system robust enough for ScopedOLEMemory
1613
+ // to handle a struct-with-flexible array member well, so we eschew it here
1614
+ // for the less-strongly-typed (and slightly more awkward) nsAutoGlobalMem.
1615
+ size_t const allocSize =
1616
+ // Size of the initial header block...
1617
+ sizeof (DFWithPaths) +
1618
+ // ... size of the first path...
1619
+ ((aPath.Length () + 1 ) * sizeof (WCHAR)) +
1620
+ // ... and size of the terminating empty string.
1621
+ sizeof (L" " );
1622
+
1623
+ nsAutoGlobalMem hGlobalMemory (
1624
+ nsHGLOBAL (::GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, allocSize)));
1625
+
1626
+ if (!hGlobalMemory) {
1627
+ return E_FAIL;
1628
+ }
1629
+
1630
+ {
1631
+ ScopedOLELock<DFWithPaths*> pDFWithPaths (hGlobalMemory.get ());
1632
+
1633
+ // First, populate the dropfile structure...
1634
+ DROPFILES* pDropFile = &pDFWithPaths->dropfiles ;
1635
+ pDropFile->pFiles =
1636
+ offsetof (DFWithPaths, paths) - offsetof (DFWithPaths, dropfiles);
1637
+ pDropFile->fNC = 0 ;
1638
+ pDropFile->pt .x = 0 ;
1639
+ pDropFile->pt .y = 0 ;
1640
+ pDropFile->fWide = TRUE ;
1641
+
1642
+ // ... then copy the filename into `paths`.
1643
+ WCHAR* dest = pDFWithPaths->paths ;
1644
+ WCHAR* after_dest [[maybe_unused]] =
1645
+ std::copy_n (aPath.BeginReading (), aPath.Length (), dest);
1646
+
1647
+ // Two NULs are needed after the file name; the GMEM_ZEROINIT above should
1648
+ // provide them.
1649
+ size_t const offset [[maybe_unused]] =
1650
+ (char *)after_dest - (char *)pDFWithPaths.get ();
1651
+ MOZ_ASSERT (allocSize - offset == sizeof (WCHAR) * 2 );
1652
+ MOZ_ASSERT (after_dest[0 ] == L' \0 ' );
1653
+ MOZ_ASSERT (after_dest[1 ] == L' \0 ' );
1654
+ }
1655
+
1656
+ aSTG = {
1657
+ .tymed = TYMED_HGLOBAL,
1658
+ .hGlobal = hGlobalMemory.disown (),
1659
+ .pUnkForRelease = nullptr ,
1660
+ };
1661
+
1662
+ return S_OK;
1663
+ }
1664
+
1602
1665
HRESULT nsDataObj::DropFile (FORMATETC& aFE, STGMEDIUM& aSTG) {
1603
1666
nsresult rv;
1604
1667
nsCOMPtr<nsISupports> genericDataWrapper;
@@ -1610,44 +1673,11 @@ HRESULT nsDataObj::DropFile(FORMATETC& aFE, STGMEDIUM& aSTG) {
1610
1673
nsCOMPtr<nsIFile> file (do_QueryInterface (genericDataWrapper));
1611
1674
if (!file) return E_FAIL;
1612
1675
1613
- aSTG.tymed = TYMED_HGLOBAL;
1614
- aSTG.pUnkForRelease = nullptr ;
1615
-
1616
1676
nsAutoString path;
1617
1677
rv = file->GetPath (path);
1618
1678
if (NS_FAILED(rv)) return E_FAIL;
1619
1679
1620
- uint32_t allocLen = path.Length () + 2 ;
1621
- HGLOBAL hGlobalMemory = nullptr ;
1622
- char16_t * dest;
1623
-
1624
- hGlobalMemory = GlobalAlloc (GMEM_MOVEABLE,
1625
- sizeof (DROPFILES) + allocLen * sizeof (char16_t ));
1626
- if (!hGlobalMemory) return E_FAIL;
1627
-
1628
- DROPFILES* pDropFile = (DROPFILES*)GlobalLock (hGlobalMemory);
1629
-
1630
- // First, populate the drop file structure
1631
- pDropFile->pFiles = sizeof (DROPFILES); // Offset to start of file name string
1632
- pDropFile->fNC = 0 ;
1633
- pDropFile->pt .x = 0 ;
1634
- pDropFile->pt .y = 0 ;
1635
- pDropFile->fWide = TRUE ;
1636
-
1637
- // Copy the filename right after the DROPFILES structure
1638
- dest = (char16_t *)(((char *)pDropFile) + pDropFile->pFiles );
1639
- memcpy (dest, path.get (), (allocLen - 1 ) * sizeof (char16_t ));
1640
-
1641
- // Two null characters are needed at the end of the file name.
1642
- // Lookup the CF_HDROP shell clipboard format for more info.
1643
- // Add the second null character right after the first one.
1644
- dest[allocLen - 1 ] = L' \0 ' ;
1645
-
1646
- GlobalUnlock (hGlobalMemory);
1647
-
1648
- aSTG.hGlobal = hGlobalMemory;
1649
-
1650
- return S_OK;
1680
+ return AssignDropfile (aSTG, path);
1651
1681
}
1652
1682
1653
1683
HRESULT nsDataObj::DropImage (FORMATETC& /* aFE */ , STGMEDIUM& aSTG) {
@@ -1750,44 +1780,7 @@ HRESULT nsDataObj::DropImage(FORMATETC& /* aFE */, STGMEDIUM& aSTG) {
1750
1780
rv = mCachedTempFile ->GetPath (path);
1751
1781
if (NS_FAILED(rv)) return E_FAIL;
1752
1782
1753
- // Two null characters are needed to terminate the file name list.
1754
- HGLOBAL hGlobalMemory = nullptr ;
1755
-
1756
- uint32_t allocLen = path.Length () + 2 ;
1757
-
1758
- aSTG.tymed = TYMED_HGLOBAL;
1759
- aSTG.pUnkForRelease = nullptr ;
1760
-
1761
- hGlobalMemory = GlobalAlloc (GMEM_MOVEABLE,
1762
- sizeof (DROPFILES) + allocLen * sizeof (char16_t ));
1763
- if (!hGlobalMemory) return E_FAIL;
1764
-
1765
- DROPFILES* pDropFile = (DROPFILES*)GlobalLock (hGlobalMemory);
1766
-
1767
- // First, populate the drop file structure.
1768
- pDropFile->pFiles =
1769
- sizeof (DROPFILES); // Offset to start of file name char array.
1770
- pDropFile->fNC = 0 ;
1771
- pDropFile->pt .x = 0 ;
1772
- pDropFile->pt .y = 0 ;
1773
- pDropFile->fWide = TRUE ;
1774
-
1775
- // Copy the filename right after the DROPFILES structure.
1776
- char16_t * dest = (char16_t *)(((char *)pDropFile) + pDropFile->pFiles );
1777
- memcpy (dest, path.get (),
1778
- (allocLen - 1 ) *
1779
- sizeof (char16_t )); // Copies the null character in path as well.
1780
-
1781
- // Two null characters are needed at the end of the file name.
1782
- // Lookup the CF_HDROP shell clipboard format for more info.
1783
- // Add the second null character right after the first one.
1784
- dest[allocLen - 1 ] = L' \0 ' ;
1785
-
1786
- GlobalUnlock (hGlobalMemory);
1787
-
1788
- aSTG.hGlobal = hGlobalMemory;
1789
-
1790
- return S_OK;
1783
+ return AssignDropfile (aSTG, path);
1791
1784
}
1792
1785
1793
1786
HRESULT nsDataObj::DropTempFile (FORMATETC& aFE, STGMEDIUM& aSTG) {
@@ -1844,44 +1837,7 @@ HRESULT nsDataObj::DropTempFile(FORMATETC& aFE, STGMEDIUM& aSTG) {
1844
1837
rv = mCachedTempFile ->GetPath (path);
1845
1838
if (NS_FAILED(rv)) return E_FAIL;
1846
1839
1847
- uint32_t allocLen = path.Length () + 2 ;
1848
-
1849
- // Two null characters are needed to terminate the file name list.
1850
- HGLOBAL hGlobalMemory = nullptr ;
1851
-
1852
- aSTG.tymed = TYMED_HGLOBAL;
1853
- aSTG.pUnkForRelease = nullptr ;
1854
-
1855
- hGlobalMemory = GlobalAlloc (GMEM_MOVEABLE,
1856
- sizeof (DROPFILES) + allocLen * sizeof (char16_t ));
1857
- if (!hGlobalMemory) return E_FAIL;
1858
-
1859
- DROPFILES* pDropFile = (DROPFILES*)GlobalLock (hGlobalMemory);
1860
-
1861
- // First, populate the drop file structure.
1862
- pDropFile->pFiles =
1863
- sizeof (DROPFILES); // Offset to start of file name char array.
1864
- pDropFile->fNC = 0 ;
1865
- pDropFile->pt .x = 0 ;
1866
- pDropFile->pt .y = 0 ;
1867
- pDropFile->fWide = TRUE ;
1868
-
1869
- // Copy the filename right after the DROPFILES structure.
1870
- char16_t * dest = (char16_t *)(((char *)pDropFile) + pDropFile->pFiles );
1871
- memcpy (dest, path.get (),
1872
- (allocLen - 1 ) *
1873
- sizeof (char16_t )); // Copies the null character in path as well.
1874
-
1875
- // Two null characters are needed at the end of the file name.
1876
- // Lookup the CF_HDROP shell clipboard format for more info.
1877
- // Add the second null character right after the first one.
1878
- dest[allocLen - 1 ] = L' \0 ' ;
1879
-
1880
- GlobalUnlock (hGlobalMemory);
1881
-
1882
- aSTG.hGlobal = hGlobalMemory;
1883
-
1884
- return S_OK;
1840
+ return AssignDropfile (aSTG, path);
1885
1841
}
1886
1842
1887
1843
// -----------------------------------------------------
0 commit comments